From fcef9eb2660f76bb7b0e1ce56f99a6864513ae59 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Feb 2018 10:37:23 +0000 Subject: [PATCH 01/99] blank slate --- example/index.html | 217 -- package.json | 49 +- src/attachment.ts | 7 - src/basic_cursor.ts | 9 - src/basic_message.ts | 13 - src/basic_message_enricher.ts | 208 -- src/basic_user.ts | 7 - src/chat_manager.ts | 141 -- src/chat_manager_delegate.ts | 24 - src/constants.ts | 2 - src/current_user.ts | 820 ------- src/cursor.ts | 12 - src/cursor_subscription.ts | 88 - src/cursor_types.ts | 5 - src/fetched_attachment.ts | 13 - src/global_user_store.ts | 171 -- src/index.ts | 12 - src/message.ts | 15 - src/payload_deserializer.ts | 255 --- src/presence_payload.ts | 9 - src/presence_state.ts | 17 - src/presence_subscription.ts | 251 --- src/room.ts | 49 - src/room_delegate.ts | 23 - src/room_store.ts | 84 - src/room_subscription.ts | 57 - src/room_user_store.ts | 18 - src/token_provider.ts | 106 - src/user.ts | 48 - src/user_store_core.ts | 36 - src/user_subscription.ts | 773 ------- src/utils.ts | 80 - tests/package.json | 29 - tests/yarn.lock | 3760 -------------------------------- tsconfig.json | 17 - tslint.json | 24 - webpack/config.react-native.js | 21 - webpack/config.shared.js | 16 - webpack/config.web.js | 17 - webpack/config.worker.js | 21 - yarn.lock | 2992 ++++++++++++++++--------- 41 files changed, 2027 insertions(+), 8489 deletions(-) delete mode 100644 example/index.html delete mode 100644 src/attachment.ts delete mode 100644 src/basic_cursor.ts delete mode 100644 src/basic_message.ts delete mode 100644 src/basic_message_enricher.ts delete mode 100644 src/basic_user.ts delete mode 100644 src/chat_manager.ts delete mode 100644 src/chat_manager_delegate.ts delete mode 100644 src/constants.ts delete mode 100644 src/current_user.ts delete mode 100644 src/cursor.ts delete mode 100644 src/cursor_subscription.ts delete mode 100644 src/cursor_types.ts delete mode 100644 src/fetched_attachment.ts delete mode 100644 src/global_user_store.ts delete mode 100644 src/index.ts delete mode 100644 src/message.ts delete mode 100644 src/payload_deserializer.ts delete mode 100644 src/presence_payload.ts delete mode 100644 src/presence_state.ts delete mode 100644 src/presence_subscription.ts delete mode 100644 src/room.ts delete mode 100644 src/room_delegate.ts delete mode 100644 src/room_store.ts delete mode 100644 src/room_subscription.ts delete mode 100644 src/room_user_store.ts delete mode 100644 src/token_provider.ts delete mode 100644 src/user.ts delete mode 100644 src/user_store_core.ts delete mode 100644 src/user_subscription.ts delete mode 100644 src/utils.ts delete mode 100644 tests/package.json delete mode 100644 tests/yarn.lock delete mode 100644 tsconfig.json delete mode 100644 tslint.json delete mode 100644 webpack/config.react-native.js delete mode 100644 webpack/config.shared.js delete mode 100644 webpack/config.web.js delete mode 100644 webpack/config.worker.js diff --git a/example/index.html b/example/index.html deleted file mode 100644 index 5c97b0b..0000000 --- a/example/index.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - - - -
- -
- + - -
-
SEND
-
- - - - - diff --git a/package.json b/package.json index 161a387..1006d0d 100644 --- a/package.json +++ b/package.json @@ -14,30 +14,35 @@ "type": "git", "url": "git+https://github.com/pusher/chatkit-client-js.git" }, - "scripts": { - "build": "yarn build:all", - "build:all": "yarn clean && yarn build:web && yarn build:react-native && yarn build:worker", - "build:web": "webpack --config=webpack/config.web.js", - "build:react-native": "webpack --config=webpack/config.react-native.js", - "build:worker": "webpack --config=webpack/config.worker.js", - "clean": "rm -rf dist", - "format": "yarn prettier --write", - "lint": "tslint -c tslint.json 'src/**/*.ts'", - "prettier": "prettier 'src/**/*.ts'" - }, "dependencies": { - "pusher-platform": "^0.14.0", - "tslint-config-prettier": "^1.6.0" + "pusher-platform": "^0.14.0" }, "devDependencies": { - "babel-core": "^6.25.0", - "babel-loader": "^7.0.0", - "babel-preset-env": "^1.6.0", - "prettier": "^1.9.1", - "ts-loader": "^2.1.0", - "tslint": "^5.8.0", - "tslint-config-prettier": "^1.6.0", - "typescript": "^2.6.1", - "webpack": "^3.8.1" + "babel-core": "^6.26.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-preset-env": "^1.6.1", + "babelify": "^8.0.0", + "browserify": "^15.2.0", + "faucet": "^0.0.1", + "pusher-chatkit-server": "^0.9.1", + "ramda": "^0.25.0", + "snazzy": "^7.0.0", + "standard": "^10.0.3", + "tape": "^4.8.0", + "tape-run": "^3.0.2" + }, + "scripts": { + "build": "echo ...", + "lint": "standard --verbose tests | snazzy", + "test": "browserify tests/main.js -t babelify | tape-run | faucet", + "lint:test": "clear && yarn lint && clear && yarn test" + }, + "babel": { + "presets": [ + "env" + ], + "plugins": [ + "transform-object-rest-spread" + ] } } diff --git a/src/attachment.ts b/src/attachment.ts deleted file mode 100644 index f8635d5..0000000 --- a/src/attachment.ts +++ /dev/null @@ -1,7 +0,0 @@ -interface Attachment { - fetchRequired: boolean; - link: string; - type: string; -} - -export default Attachment; diff --git a/src/basic_cursor.ts b/src/basic_cursor.ts deleted file mode 100644 index e7a0d75..0000000 --- a/src/basic_cursor.ts +++ /dev/null @@ -1,9 +0,0 @@ -interface BasicCursor { - cursorType: number; - position: number; - roomId: number; - updatedAt: string; - userId: string; -} - -export default BasicCursor; diff --git a/src/basic_message.ts b/src/basic_message.ts deleted file mode 100644 index be0ffda..0000000 --- a/src/basic_message.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Attachment from './attachment'; - -interface BasicMessage { - id: number; - senderId: string; - roomId: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; -} - -export default BasicMessage; diff --git a/src/basic_message_enricher.ts b/src/basic_message_enricher.ts deleted file mode 100644 index f844b69..0000000 --- a/src/basic_message_enricher.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { Logger } from 'pusher-platform'; - -import BasicMessage from './basic_message'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import Room from './room'; -import User from './user'; - -export interface MessageEnrichmentCompletionHandlers { - onSuccess: (message: Message) => void; - onError: (error: any) => void; -} - -export type MessageIdsToCompletionHandlers = { - [key: number]: MessageEnrichmentCompletionHandlers; -}; - -export type UserIdsToBasicMessageIds = { - [key: string]: number[]; -}; - -export type MessageEnrichmentResult = Message | any; - -export type MessageIdsToEnrichmentResults = { - [key: number]: MessageEnrichmentResult; -}; - -export type MessageIdsToBasicMessages = { - [key: number]: BasicMessage; -}; - -export default class BasicMessageEnricher { - userStore: GlobalUserStore; - room: Room; - logger: Logger; - - private completionOrderList: number[] = []; - private messageIdToCompletionHandlers: MessageIdsToCompletionHandlers = {}; - private enrichedMessagesAwaitingCompletionCalls: MessageIdsToEnrichmentResults = {}; - - private userIdsBeingRetrieved: string[] = []; - private userIdsToBasicMessageIds: UserIdsToBasicMessageIds = {}; - private messagesAwaitingEnrichmentDependentOnUserRetrieval: MessageIdsToBasicMessages = {}; - - constructor(userStore: GlobalUserStore, room: Room, logger: Logger) { - this.userStore = userStore; - this.room = room; - this.logger = logger; - } - - enrich( - basicMessage: BasicMessage, - onSuccess: (message: Message) => void, - onError: (error: any) => void, - ) { - const basicMessageId = basicMessage.id; - const basicMessageSenderId = basicMessage.senderId; - - this.completionOrderList.push(basicMessageId); - this.messageIdToCompletionHandlers[basicMessageId] = { - onError, - onSuccess, - }; - - if (this.userIdsToBasicMessageIds[basicMessageSenderId] === undefined) { - this.userIdsToBasicMessageIds[basicMessageSenderId] = [basicMessageId]; - } else { - this.userIdsToBasicMessageIds[basicMessageSenderId].push(basicMessageId); - } - - this.messagesAwaitingEnrichmentDependentOnUserRetrieval[ - basicMessageId - ] = basicMessage; - - if (this.userIdsBeingRetrieved.indexOf(basicMessageSenderId) > -1) { - return; - } else { - this.userIdsBeingRetrieved.push(basicMessageSenderId); - } - - this.userStore.user( - basicMessageSenderId, - user => { - const basicMessageIds = this.userIdsToBasicMessageIds[ - basicMessageSenderId - ]; - - if (basicMessageIds === undefined) { - this.logger.verbose( - `Fetched user information for user with id ${ - user.id - } but no messages needed information for this user`, - ); - return; - } - - // TODO: Is this right? - const basicMessages = basicMessageIds - .map(bmId => { - return this.messagesAwaitingEnrichmentDependentOnUserRetrieval[ - bmId - ]; - }) - .filter(el => el !== undefined); - - this.enrichMessagesWithUser(user, basicMessages); - - const indexToRemove = this.userIdsBeingRetrieved.indexOf( - basicMessageSenderId, - ); - if (indexToRemove > -1) { - this.userIdsBeingRetrieved.splice(indexToRemove, 1); - } - }, - error => { - this.logger.debug( - `Unable to find user with id ${ - basicMessage.senderId - }, associated with message ${basicMessageId}. Error:`, - error, - ); - this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo( - basicMessageId, - error, - ); - }, - ); - } - - enrichMessagesWithUser(user: User, messages: BasicMessage[]) { - messages.forEach(basicMessage => { - const message = { - attachment: basicMessage.attachment, - createdAt: basicMessage.createdAt, - id: basicMessage.id, - room: this.room, - sender: user, - text: basicMessage.text, - updatedAt: basicMessage.updatedAt, - }; - this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo( - basicMessage.id, - message, - ); - }); - } - - callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo( - id: number, - result: MessageEnrichmentResult, - ) { - // TODO: There may well be ways to make this faster - const nextIdToComplete = this.completionOrderList[0]; - if (nextIdToComplete === undefined) { - return; - } - - this.enrichedMessagesAwaitingCompletionCalls[id] = result; - - if (id !== nextIdToComplete) { - // If the message id received isn't the next to have its completionHandler called - // then return as we've already stored the result so it can be used later - // TODO: Fixme - this.logger.verbose( - `Waiting to call completion handler for message id ${id} as there are other older messages still to be enriched`, - ); - return; - } - - do { - // TODO: I think this could get stuck in a loop forever if there's no - // completion handler stored for a message with a given id - const messageId = this.completionOrderList[0]; - - const completionHandler = this.messageIdToCompletionHandlers[messageId]; - if (completionHandler === undefined) { - this.logger.verbose( - `Completion handler not stored for message id ${messageId}`, - ); - return; - } - - const res = this.enrichedMessagesAwaitingCompletionCalls[messageId]; - if (res === undefined) { - this.logger.verbose( - `Enrichment result not stored for message id ${messageId}`, - ); - return; - } - - // TODO: PROPERLY CHECK IF IT'S A MESSAGE OR AN ERROR - NOT THIS FILTHY HACK - if (res.sender !== undefined) { - completionHandler.onSuccess(res); - } else { - completionHandler.onError(res); - } - - this.completionOrderList.shift(); - delete this.messageIdToCompletionHandlers[messageId]; - delete this.enrichedMessagesAwaitingCompletionCalls[messageId]; - } while ( - this.completionOrderList[0] !== undefined && - this.enrichedMessagesAwaitingCompletionCalls[ - this.completionOrderList[0] - ] !== undefined - ); - } -} diff --git a/src/basic_user.ts b/src/basic_user.ts deleted file mode 100644 index 75f936f..0000000 --- a/src/basic_user.ts +++ /dev/null @@ -1,7 +0,0 @@ -interface BasicUser { - id: string; - createdAt: string; - updatedAt: string; -} - -export default BasicUser; diff --git a/src/chat_manager.ts b/src/chat_manager.ts deleted file mode 100644 index 556d5f2..0000000 --- a/src/chat_manager.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - BaseClient, - HOST_BASE, - Instance, - Logger, - TokenProvider, -} from 'pusher-platform'; - -import BasicCursor from './basic_cursor'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -import GlobalUserStore from './global_user_store'; -import PayloadDeserializer from './payload_deserializer'; -import CKTokenProvider from './token_provider'; -import UserSubscription from './user_subscription'; - -export interface ChatManagerOptions { - instanceLocator: string; - tokenProvider: TokenProvider; - logger?: Logger; - baseClient?: BaseClient; - userId: string; -} - -export default class ChatManager { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userId: string; - - private userStore: GlobalUserStore; - private userSubscription: UserSubscription; - - constructor(options: ChatManagerOptions) { - if (typeof options.userId !== 'string') { - throw new Error('Please provide a userId to the ChatManger constructor!'); - } - this.userId = options.userId; - const splitInstanceLocator = options.instanceLocator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instanceLocator property is in the wrong format!'); - } - const cluster = splitInstanceLocator[1]; - const baseClient = - options.baseClient || - new BaseClient({ - host: `${cluster}.${HOST_BASE}`, - logger: options.logger, - }); - - if (options.tokenProvider instanceof CKTokenProvider) { - options.tokenProvider.userId = this.userId; - } - const sharedInstanceOptions = { - client: baseClient, - locator: options.instanceLocator, - logger: options.logger, - tokenProvider: options.tokenProvider, - }; - - this.apiInstance = new Instance({ - serviceName: 'chatkit', - serviceVersion: 'v1', - ...sharedInstanceOptions, - }); - - this.filesInstance = new Instance({ - serviceName: 'chatkit_files', - serviceVersion: 'v1', - ...sharedInstanceOptions, - }); - - this.cursorsInstance = new Instance({ - serviceName: 'chatkit_cursors', - serviceVersion: 'v1', - ...sharedInstanceOptions, - }); - - this.userStore = new GlobalUserStore({ apiInstance: this.apiInstance }); - } - - connect(options: ConnectOptions) { - const cursorsReq: Promise<{ - [roomId: number]: BasicCursor; - }> = this.cursorsInstance - .request({ - method: 'GET', - path: `/cursors/0/users/${this.userId}`, - }) - .then(res => { - const cursors = JSON.parse(res); - const cursorsByRoom: { [roomId: number]: BasicCursor } = {}; - cursors.forEach((c: any): void => { - cursorsByRoom[ - c.room_id - ] = PayloadDeserializer.createBasicCursorFromPayload(c); - }); - return cursorsByRoom; - }) - .catch(err => { - this.cursorsInstance.logger.verbose( - 'Error getting cursors:', - err, - ); - return {} - }); - - this.userSubscription = new UserSubscription({ - apiInstance: this.apiInstance, - connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => { - if (currentUser) { - currentUser.cursorsReq = cursorsReq - .then(cursors => { - currentUser.cursors = cursors; - }); - options.onSuccess(currentUser); - } else { - options.onError(error); - } - }, - cursorsInstance: this.cursorsInstance, - delegate: options.delegate, - filesInstance: this.filesInstance, - userStore: this.userStore, - }); - - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: options.onError, - onEvent: this.userSubscription.handleEvent.bind(this.userSubscription), - }, - path: '/users', - }); - } -} - -export interface ConnectOptions { - delegate?: ChatManagerDelegate; - onSuccess: (currentUser: CurrentUser) => void; - onError: (error: any) => void; -} diff --git a/src/chat_manager_delegate.ts b/src/chat_manager_delegate.ts deleted file mode 100644 index e5eafe2..0000000 --- a/src/chat_manager_delegate.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Room from './room'; -import User from './user'; - -interface ChatManagerDelegate { - addedToRoom?: (room: Room) => void; - removedFromRoom?: (room: Room) => void; - roomUpdated?: (room: Room) => void; - roomDeleted?: (room: Room) => void; - - // These _can_ be implemented as part of the ChatManagerDelegate, but - // the primary usage is intended at the Room level (see RoomDelegate) - userStartedTyping?: (room: Room, user: User) => void; - userStoppedTyping?: (room: Room, user: User) => void; - userJoinedRoom?: (room: Room, user: User) => void; - userLeftRoom?: (room: Room, user: User) => void; - userCameOnline?: (user: User) => void; - userWentOffline?: (user: User) => void; - - // TODO: Is this the best way of communicating errors? What errors are - // communicated using this? - error?: (error: any) => void; -} - -export default ChatManagerDelegate; diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 9e8dee6..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const TYPING_REQ_TTL = 1500; -export const TYPING_REQ_LEEWAY = 500; diff --git a/src/current_user.ts b/src/current_user.ts deleted file mode 100644 index c5a5f4d..0000000 --- a/src/current_user.ts +++ /dev/null @@ -1,820 +0,0 @@ -import { Instance, sendRawRequest } from 'pusher-platform'; - -import BasicCursor from './basic_cursor'; -import BasicMessage from './basic_message'; -import BasicMessageEnricher from './basic_message_enricher'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CursorSubscription from './cursor_subscription'; -import CursorType from './cursor_types'; -import FetchedAttachment from './fetched_attachment'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import PayloadDeserializer from './payload_deserializer'; -import PresenceSubscription from './presence_subscription'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -import RoomStore from './room_store'; -import RoomSubscription from './room_subscription'; - -import { TYPING_REQ_LEEWAY, TYPING_REQ_TTL } from './constants'; -import { allPromisesSettled } from './utils'; - -export interface CreateRoomOptions { - name: string; - private?: boolean; - addUserIds?: string[]; -} - -export interface UpdateRoomOptions { - name?: string; - isPrivate?: boolean; -} - -export interface FetchRoomMessagesOptions { - initialId?: string; - limit?: number; - direction?: string; -} - -export interface CurrentUserOptions { - id: string; - createdAt: string; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; // TODO: Shouldn't be any (type) - rooms?: Room[]; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; -} - -export interface DataAttachment { - file: Blob; - name: string; -} - -export interface LinkAttachment { - link: string; - type: string; -} - -export type GenericAttachment = LinkAttachment | DataAttachment; - -export interface AttachmentBody { - resource_link: string; - type: string; -} - -export interface SendMessageOptions { - attachment?: GenericAttachment; - roomId: number; - text?: string; -} - -export interface CompleteMessageOptions { - attachment?: AttachmentBody; - roomId: number; - text?: string; - user_id: string; -} - -export default class CurrentUser { - id: string; - createdAt: string; - cursors: { [roomId: string]: BasicCursor }; - cursorsReq: Promise; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - userStore: GlobalUserStore; - roomStore: RoomStore; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - pathFriendlyId: string; - presenceSubscription: PresenceSubscription; - typingRequestSent: { [roomId: string]: number }; - - get rooms(): Room[] { - return this.roomStore.rooms; - } - - constructor(options: CurrentUserOptions) { - const { rooms, id, apiInstance, filesInstance, cursorsInstance } = options; - const validRooms: Room[] = rooms || []; - - this.id = id; - this.createdAt = options.createdAt; - this.cursors = {}; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.roomStore = new RoomStore({ apiInstance, rooms: validRooms }); - this.apiInstance = apiInstance; - this.filesInstance = filesInstance; - this.cursorsInstance = cursorsInstance; - this.userStore = options.userStore; - this.pathFriendlyId = encodeURIComponent(id); // TODO: This is different to Swift SDK - this.typingRequestSent = {}; - } - - updateWithPropertiesOf(currentUser: CurrentUser) { - this.updatedAt = currentUser.updatedAt; - this.name = currentUser.name; - this.customData = currentUser.customData; - } - - setupPresenceSubscription(delegate?: ChatManagerDelegate) { - this.presenceSubscription = new PresenceSubscription({ - apiInstance: this.apiInstance, - delegate, - roomStore: this.roomStore, - userStore: this.userStore, - }); - - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: delegate && delegate.error, - onEvent: this.presenceSubscription.handleEvent.bind( - this.presenceSubscription, - ), - }, - path: `/users/${this.id}/presence`, - }); - } - - createRoom( - options: CreateRoomOptions, - onSuccess: (room: Room) => void, - onError: (error: any) => void, - ) { - const roomData: any = { - created_by_id: this.id, - name: options.name, - private: options.private || false, - }; - - if (options.addUserIds && options.addUserIds.length > 0) { - // tslint:disable-next-line:no-string-literal - roomData['user_ids'] = options.addUserIds; - } - - this.apiInstance - .request({ - json: roomData, - method: 'POST', - path: '/rooms', - }) - .then((res: any) => { - const roomPayload = JSON.parse(res); - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - const addedOrMergedRoom = this.roomStore.addOrMerge(room); - this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose('Error creating room:', error); - onError(error); - }); - } - - populateRoomUserStore(room: Room) { - // TODO: Use the soon-to-be-created new version of fetchUsersWithIds from the userStore - - const userPromises = new Array>(); - - room.userIds.forEach(userId => { - const userPromise = new Promise((resolve, reject) => { - this.userStore.user( - userId, - user => { - room.userStore.addOrMerge(user); - resolve(); - }, - error => { - this.apiInstance.logger.debug( - `Unable to add user with id ${userId} to room \(room.name): ${error}`, - ); - reject(); - }, - ); - }); - - userPromises.push(userPromise); - }); - - allPromisesSettled(userPromises).then(() => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - - this.apiInstance.logger.verbose(`Users updated in room ${room.name}`); - }); - } - - addUser( - id: string, - roomId: number, - onSuccess: () => void, - onError: (error: any) => void, - ) { - this.addOrRemoveUsers(roomId, [id], 'add', onSuccess, onError); - } - - // addUsers(ids: [string], roomId: number, onSuccess: () => void, onError: (error: any) => void) { - // this.addOrRemoveUsers(roomId, ids, 'add', onSuccess, onError); - // } - - removeUser( - id: string, - roomId: number, - onSuccess: () => void, - onError: (error: any) => void, - ) { - this.addOrRemoveUsers(roomId, [id], 'remove', onSuccess, onError); - } - - // removeUsers(ids: string[], roomId: number, onSuccess: () => void, onError: (error: any) => void) { - // this.addOrRemoveUsers(roomId, ids, 'remove', onSuccess, onError); - // } - - updateRoom( - roomId: number, - options: UpdateRoomOptions, - onSuccess: () => void, - onError: (error: any) => void, - ) { - if (options.name === undefined && options.isPrivate === undefined) { - onSuccess(); - return; - } - - const roomPayload: any = {}; - if (options.name) { - // tslint:disable-next-line:no-string-literal - roomPayload['name'] = options.name; - } - if (options.isPrivate) { - // tslint:disable-next-line:no-string-literal - roomPayload['private'] = options.isPrivate; - } - - this.apiInstance - .request({ - json: roomPayload, - method: 'PUT', - path: `/rooms/${roomId}`, - }) - .then((res: any) => { - onSuccess(); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - `Error updating room ${roomId}:`, - error, - ); - onError(error); - }); - } - - deleteRoom( - roomId: number, - onSuccess: () => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - method: 'DELETE', - path: `/rooms/${roomId}`, - }) - .then((res: any) => { - onSuccess(); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - `Error deleting room ${roomId}:`, - error, - ); - onError(error); - }); - } - - addOrRemoveUsers( - roomId: number, - userIds: string[], - membershipChange: string, - onSuccess: () => void, - onError: (error: any) => void, - ) { - const usersPayload = { - user_ids: userIds, - }; - - this.apiInstance - .request({ - json: usersPayload, - method: 'PUT', - path: `/rooms/${roomId}/users/${membershipChange}`, - }) - .then((res: any) => { - onSuccess(); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - `Error when attempting to ${membershipChange} users from room ${roomId}:`, - error, - ); - onError(error); - }); - } - - joinRoom( - roomId: number, - onSuccess: (room: Room) => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - method: 'POST', - path: `/users/${this.pathFriendlyId}/rooms/${roomId}/join`, - }) - .then((res: any) => { - const roomPayload = JSON.parse(res); - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - const addedOrMergedRoom = this.roomStore.addOrMerge(room); - // TODO: room or addedOrMergedRoom ? - this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose(`Error joining room ${roomId}:`, error); - onError(error); - }); - } - - leaveRoom( - roomId: number, - onSuccess: () => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - method: 'POST', - path: `/users/${this.pathFriendlyId}/rooms/${roomId}/leave`, - }) - .then((res: any) => { - // TODO: Remove room from roomStore or is that handle by UserSubscription? - onSuccess(); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose(`Error leaving room ${roomId}:`, error); - onError(error); - }); - } - - getJoinedRooms( - onSuccess: (rooms: Room[]) => void, - onError: (error: any) => void, - ) { - this.getUserRooms(false, onSuccess, onError); - } - - getJoinableRooms( - onSuccess: (rooms: Room[]) => void, - onError: (error: any) => void, - ) { - this.getUserRooms(true, onSuccess, onError); - } - - getUserRooms( - onlyJoinable: boolean, - onSuccess: (rooms: Room[]) => void, - onError: (error: any) => void, - ) { - const joinableQueryItemValue = onlyJoinable ? 'true' : 'false'; - this.getRooms( - `/users/${this.pathFriendlyId}/rooms?joinable=${joinableQueryItemValue}`, - onSuccess, - onError, - ); - } - - getAllRooms( - onSuccess: (rooms: Room[]) => void, - onError: (error: any) => void, - ) { - this.getRooms('/rooms', onSuccess, onError); - } - - isTypingIn( - roomId: number, - onSuccess: () => void, - onError: (error: any) => void, - ) { - const now = Date.now(); - const sent = this.typingRequestSent[roomId]; - const eventName = 'typing_start'; - const eventPayload = { - // TODO this would ideally be is_typing or typing_heartbeat or some such - name: 'typing_start', - user_id: this.id, - }; - if (!sent || now - sent > TYPING_REQ_TTL - TYPING_REQ_LEEWAY) { - this.typingRequestSent[roomId] = now; - this.apiInstance - .request({ - json: eventPayload, - method: 'POST', - path: `/rooms/${roomId}/events`, - }) - .then((res: any) => { - onSuccess(); - }) - .catch((error: any) => { - delete this.typingRequestSent[roomId]; - this.apiInstance.logger.verbose( - `Error sending ${eventName} event in room ${roomId}:`, - error, - ); - onError(error); - }); - } else { - onSuccess(); - } - } - - setCursor( - position: number, - room: Room, - onSuccess: () => void, - onError: (error: any) => void, - ) { - if (typeof position !== 'number') { - throw new Error('Cursor position should be a valid number'); - } - - this.cursorsInstance - .request({ - json: { position }, - method: 'PUT', - path: `/cursors/${CursorType.Read}/rooms/${room.id}/users/${this.id}`, - }) - .then(onSuccess) - .catch(err => { - this.cursorsInstance.logger.verbose( - `Error setting cursor in room ${room.name}:`, - err, - ); - onError(err); - }); - } - - sendMessage( - options: SendMessageOptions, - onSuccess: (messageId: number) => void, - onError: (error: any) => void, - ) { - const { attachment, ...rest } = options; - const completeOptions: CompleteMessageOptions = { - user_id: this.id, - ...rest, - }; - - if (attachment !== undefined) { - if (this.isDataAttachment(attachment)) { - const { file, name } = attachment; - this.uploadFile(file, name, options.roomId) - .then((fileRes: any) => { - this.sendMessageWithCompleteOptions( - { - attachment: fileRes, - user_id: this.id, - ...rest, - }, - onSuccess, - onError, - ); - }) - .catch((error: any) => { - onError(error); - return; - }); - } else if (this.isLinkAttachment(attachment)) { - const { link, type } = attachment; - completeOptions.attachment = { - resource_link: link, - type, - }; - this.sendMessageWithCompleteOptions( - completeOptions, - onSuccess, - onError, - ); - } else { - this.apiInstance.logger.debug( - 'Message not sent: invalid attachment property provided: ', - attachment, - ); - } - } else { - this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); - } - } - - subscribeToRoom( - room: Room, - roomDelegate: RoomDelegate, - messageLimit?: number, - ) { - let path = `/rooms/${room.id}`; - if (messageLimit !== undefined) { - if (typeof messageLimit !== 'number') { - throw new Error('Message limit should be a valid number'); - } - path = `${path}?message_limit=${messageLimit}`; - } - - this.cursorsReq.then(() => { - room.subscription = new RoomSubscription({ - basicMessageEnricher: new BasicMessageEnricher( - this.userStore, - room, - this.apiInstance.logger, - ), - delegate: roomDelegate, - logger: this.apiInstance.logger, - }); - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: roomDelegate.error, - onEvent: room.subscription.handleEvent.bind(room.subscription), - }, - path, - }); - this.subscribeToCursors(room, roomDelegate); - }); - } - - fetchMessagesFromRoom( - room: Room, - fetchOptions: FetchRoomMessagesOptions, - onSuccess: (messages: Message[]) => void, - onError: (error: any) => void, - ) { - const initialIdQueryParam = fetchOptions.initialId - ? `initial_id=${fetchOptions.initialId}` - : ''; - const limitQueryParam = fetchOptions.limit - ? `limit=${fetchOptions.limit}` - : ''; - const directionQueryParam = fetchOptions.direction - ? `direction=${fetchOptions.direction}` - : 'direction=older'; - - const combinedQueryParams = [ - initialIdQueryParam, - limitQueryParam, - directionQueryParam, - ].join('&'); - - this.apiInstance - .request({ - method: 'GET', - path: `/rooms/${room.id}/messages?${combinedQueryParams}`, - }) - .then((res: any) => { - const messagesPayload = JSON.parse(res); - - const messages = new Array(); - const basicMessages = new Array(); - - // TODO: Error handling - const messageUserIds = messagesPayload.map((messagePayload: any) => { - const basicMessage = PayloadDeserializer.createBasicMessageFromPayload( - messagePayload, - ); - basicMessages.push(basicMessage); - return basicMessage.id; - }); - - const messageUserIdsSet = new Set(messageUserIds); - const userIdsToFetch = Array.from(messageUserIdsSet.values()); - - this.userStore.fetchUsersWithIds( - userIdsToFetch, - users => { - const messageEnricher = new BasicMessageEnricher( - this.userStore, - room, - this.apiInstance.logger, - ); - const enrichmentPromises = new Array>(); - - basicMessages.forEach(basicMessage => { - const enrichmentPromise = new Promise((resolve, reject) => { - messageEnricher.enrich( - basicMessage, - message => { - messages.push(message); - resolve(); - }, - error => { - this.apiInstance.logger.verbose( - `Unable to enrich basic mesage ${ - basicMessage.id - }: ${error}`, - ); - reject(); - }, - ); - }); - - enrichmentPromises.push(enrichmentPromise); - }); - - allPromisesSettled(enrichmentPromises).then(() => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - - this.apiInstance.logger.verbose( - `Users updated in room ${room.name}`, - ); - - onSuccess( - messages.sort((msgOne, msgTwo) => msgOne.id - msgTwo.id), - ); - }); - }, - error => { - this.apiInstance.logger.verbose( - `Error fetching users with ids ${userIdsToFetch}:`, - error, - ); - }, - ); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - `Error fetching messages froom room ${room.name}:`, - error, - ); - onError(error); - }); - } - - fetchAttachment(attachmentURL: string): Promise { - if (!this.apiInstance.tokenProvider) { - return new Promise((resolve, reject) => { - reject(new Error('Token provider not set on apiInstance')); - }); - } - - return this.apiInstance.tokenProvider.fetchToken().then((token: string) => { - return sendRawRequest({ - headers: { - Authorization: `Bearer ${token}`, - }, - method: 'GET', - url: attachmentURL, - }).then((res: any) => { - const attachmentPayload = JSON.parse(res); - const fetchedAttachment = PayloadDeserializer.createFetchedAttachmentFromPayload( - attachmentPayload, - ); - - return fetchedAttachment; - }); - }); - } - - private isDataAttachment(attachment: any): attachment is DataAttachment { - return ( - (attachment as DataAttachment).file !== undefined && - (attachment as DataAttachment).name !== undefined - ); - } - - private isLinkAttachment(attachment: any): attachment is LinkAttachment { - return ( - (attachment as LinkAttachment).link !== undefined && - (attachment as LinkAttachment).type !== undefined - ); - } - - private uploadFile( - file: any, - fileName: string, - roomId: number, - ): Promise { - const data = new FormData(); - data.append('file', file, fileName); - - return this.filesInstance - .request({ - body: data, - method: 'POST', - path: `/rooms/${roomId}/files/${fileName}`, - }) - .then((res: any) => { - return JSON.parse(res); - }); - } - - private sendMessageWithCompleteOptions( - options: CompleteMessageOptions, - onSuccess: (messageId: number) => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - json: options, - method: 'POST', - path: `/rooms/${options.roomId}/messages`, - }) - .then((res: any) => { - const messageIdPayload = JSON.parse(res); - const messageId = messageIdPayload.message_id; - onSuccess(messageId); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - `Error sending message to room ${options.roomId}:`, - error, - ); - onError(error); - }); - } - - private subscribeToCursors(room: Room, roomDelegate: RoomDelegate) { - room.cursorSubscription = new CursorSubscription({ - delegate: roomDelegate, - handleCursorSetInternal: (cursor: BasicCursor) => { - if (cursor.userId === this.id && this.cursors !== undefined) { - this.cursors[cursor.roomId] = cursor; - } - }, - logger: this.cursorsInstance.logger, - room, - userStore: this.userStore, - }); - - this.cursorsInstance.subscribeNonResuming({ - listeners: { - onEvent: room.cursorSubscription.handleEvent.bind( - room.cursorSubscription, - ), - }, - path: `/cursors/${CursorType.Read}/rooms/${room.id}`, - }); - } - - private getRooms( - path: string, - onSuccess: (rooms: Room[]) => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - method: 'GET', - path, - }) - .then((res: any) => { - const roomsPayload = JSON.parse(res); - const rooms = roomsPayload.map((roomPayload: any) => { - return PayloadDeserializer.createRoomFromPayload(roomPayload); - }); - // TODO: filter if undefined returned? - onSuccess(rooms); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - 'Error when getting instance rooms:', - error, - ); - onError(error); - }); - } -} diff --git a/src/cursor.ts b/src/cursor.ts deleted file mode 100644 index 92993e9..0000000 --- a/src/cursor.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Room from './room'; -import User from './user'; - -interface Cursor { - cursorType: number; - position: number; - room: Room; - updatedAt: string; - user: User; -} - -export default Cursor; diff --git a/src/cursor_subscription.ts b/src/cursor_subscription.ts deleted file mode 100644 index 9ed14c0..0000000 --- a/src/cursor_subscription.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Instance, Logger, SubscriptionEvent } from 'pusher-platform'; - -import BasicCursor from './basic_cursor'; -import Cursor from './cursor'; -import GlobalUserStore from './global_user_store'; -import PayloadDeserializer from './payload_deserializer'; -import Room from './room'; -import RoomDelegate from './room_delegate'; - -export interface CursorSubscriptionOptions { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; -} - -export default class CursorSubscription { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; - - constructor(options: CursorSubscriptionOptions) { - this.delegate = options.delegate; - this.logger = options.logger; - this.room = options.room; - this.userStore = options.userStore; - this.handleCursorSetInternal = options.handleCursorSetInternal; - } - - handleEvent(event: SubscriptionEvent) { - if (!this.delegate || !this.delegate.cursorSet) { - return; - } - const { body, eventId, headers } = event; - const { data } = body; - const eventName = body.event_name; - if (eventName !== 'cursor_set') { - this.logger.verbose( - `Cursor subscription received event with type ${eventName}, when 'cursor_set' was expected`, - ); - return; - } - this.logger.verbose(`Received event name: ${eventName}, and data: ${data}`); - const basicCursor = PayloadDeserializer.createBasicCursorFromPayload(data); - this.logger.verbose(`Room received cursor for: ${basicCursor.userId}`); - this.handleCursorSetInternal(basicCursor); - this.enrich( - basicCursor, - cursor => { - if (this.delegate && this.delegate.cursorSet) { - this.delegate.cursorSet(cursor); - } - }, - error => { - this.logger.debug('Error receiving cursor:', error); - }, - ); - } - - enrich( - basicCursor: BasicCursor, - onSuccess: (cursor: Cursor) => void, - onError: (error: any) => void, - ) { - this.userStore.user( - basicCursor.userId, - user => { - onSuccess({ - cursorType: basicCursor.cursorType, - position: basicCursor.position, - room: this.room, - updatedAt: basicCursor.updatedAt, - user, - }); - }, - error => { - this.logger.debug( - `Unable to find user with id ${basicCursor.userId}. Error:`, - error, - ); - onError(error); - }, - ); - } -} diff --git a/src/cursor_types.ts b/src/cursor_types.ts deleted file mode 100644 index 97b4689..0000000 --- a/src/cursor_types.ts +++ /dev/null @@ -1,5 +0,0 @@ -enum CursorType { - Read, -} - -export default CursorType; diff --git a/src/fetched_attachment.ts b/src/fetched_attachment.ts deleted file mode 100644 index 16ebc4c..0000000 --- a/src/fetched_attachment.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface FetchedAttachmentFile { - bytes: number; - lastModified: number; - name: string; -} - -interface FetchedAttachment { - file: FetchedAttachmentFile; - link: string; - ttl: number; -} - -export default FetchedAttachment; diff --git a/src/global_user_store.ts b/src/global_user_store.ts deleted file mode 100644 index 45dde2b..0000000 --- a/src/global_user_store.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { Instance } from 'pusher-platform'; - -import PayloadDeserializer from './payload_deserializer'; -import PresencePayload from './presence_payload'; -import User from './user'; -import UserStoreCore from './user_store_core'; - -import { allPromisesSettled, queryString } from './utils'; - -export interface GlobalUserStoreOptions { - apiInstance: Instance; - userStoreCore?: UserStoreCore; -} - -export default class GlobalUserStore { - private apiInstance: Instance; - private userStoreCore: UserStoreCore; - - constructor(options: GlobalUserStoreOptions) { - this.apiInstance = options.apiInstance; - this.userStoreCore = options.userStoreCore || new UserStoreCore(); - } - - addOrMerge(user: User): User { - return this.userStoreCore.addOrMerge(user); - } - - remove(id: string): User | undefined { - return this.userStoreCore.remove(id); - } - - user( - id: string, - onSuccess: (user: User) => void, - onError: (error: any) => void, - ) { - this.findOrGetUser(id, onSuccess, onError); - } - - findOrGetUser( - id: string, - onSuccess: (user: User) => void, - onError: (error: any) => void, - ) { - const user = this.userStoreCore.find(id); - if (user) { - onSuccess(user); - return; - } - - this.getUser(id, onSuccess, onError); - } - - getUser( - id: string, - onSuccess: (user: User) => void, - onError: (error: any) => void, - ) { - this.apiInstance - .request({ - method: 'GET', - path: `/users/${id}`, - }) - .then((res: any) => { - const userPayload = JSON.parse(res); - const user = PayloadDeserializer.createUserFromPayload(userPayload); - const userToReturn = this.addOrMerge(user); - onSuccess(userToReturn); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - 'Error fetching user information:', - error, - ); - onError(error); - }); - } - - handleInitialPresencePayloadsAfterRoomJoin( - payloads: PresencePayload[], - onComplete: () => void, - ) { - this.handleInitialPresencePayloads(payloads, onComplete); - } - - handleInitialPresencePayloads( - payloads: PresencePayload[], - onComplete: () => void, - ) { - const presencePayloadPromises = new Array>(); - - payloads.forEach(payload => { - const presencePromise = new Promise((resolve, reject) => { - this.user( - payload.userId, - user => { - user.updatePresenceInfoIfAppropriate(payload); - resolve(); - }, - error => { - this.apiInstance.logger.verbose( - 'Error fetching user information:', - error, - ); - reject(); - }, - ); - }); - - presencePayloadPromises.push(presencePromise); - }); - - allPromisesSettled(presencePayloadPromises).then(() => { - onComplete(); - }); - } - - // TODO: Need a version of this that first checks the userStore for any of the userIds - // provided and then only makes a request to fetch the user information for the userIds - // that aren't known about. This would be used in the creatRoom callback and the - // addedToRoom parsing function - fetchUsersWithIds( - userIds: string[], - onSuccess: (users: User[]) => void, - onError: (error: Error) => void, - ) { - if (userIds.length === 0) { - this.apiInstance.logger.verbose( - 'Requested to fetch users for a list of user ids which was empty', - ); - onSuccess([]); - return; - } - - const userIdsString = userIds.join(','); - const qs = queryString({ user_ids: userIdsString }); - - this.apiInstance - .request({ - method: 'GET', - path: `/users_by_ids${qs}`, - }) - .then((res: any) => { - const usersPayload = JSON.parse(res); - - // TODO: Make it more like flatMap, or handle errors being thrown? - const users = usersPayload.map((userPayload: any) => { - const user = PayloadDeserializer.createUserFromPayload(userPayload); - const addedOrUpdatedUser = this.userStoreCore.addOrMerge(user); - return addedOrUpdatedUser; - }); - - onSuccess(users); - }) - .catch((error: any) => { - this.apiInstance.logger.verbose( - 'Error fetching user information:', - error, - ); - onError(error); - }); - } - - initialFetchOfUsersWithIds( - userIds: string[], - onSuccess: (users: User[]) => void, - onError: (error: Error) => void, - ) { - this.fetchUsersWithIds(userIds, onSuccess, onError); - } -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 39c8e2f..0000000 --- a/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { BaseClient } from 'pusher-platform'; - -import ChatManager from './chat_manager'; -import TokenProvider from './token_provider'; - -export { BaseClient, ChatManager, TokenProvider }; - -export default { - BaseClient, - ChatManager, - TokenProvider, -}; diff --git a/src/message.ts b/src/message.ts deleted file mode 100644 index 070f294..0000000 --- a/src/message.ts +++ /dev/null @@ -1,15 +0,0 @@ -import Attachment from './attachment'; -import Room from './room'; -import User from './user'; - -interface Message { - id: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; - sender: User; - room: Room; -} - -export default Message; diff --git a/src/payload_deserializer.ts b/src/payload_deserializer.ts deleted file mode 100644 index 8d1d83d..0000000 --- a/src/payload_deserializer.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { Instance } from 'pusher-platform'; - -import Attachment from './attachment'; -import BasicCursor from './basic_cursor'; -import BasicMessage from './basic_message'; -import BasicUser from './basic_user'; -import CurrentUser from './current_user'; -import FetchedAttachment from './fetched_attachment'; -import GlobalUserStore from './global_user_store'; -import PresencePayload from './presence_payload'; -import PresenceState from './presence_state'; -import Room from './room'; -import User from './user'; -import { queryParamsFromFullUrl } from './utils'; - -const checkPresenceAndTypeOfFieldsInPayload = ( - requiredFieldsWithTypes: any, - payload: any, -): void => { - Object.keys(requiredFieldsWithTypes).forEach(key => { - if (payload[key] === undefined) { - throw new Error(`Payload missing key: ${key}`); - } - - const receivedType = typeof payload[key]; - const expectedType = requiredFieldsWithTypes[key]; - - if (receivedType !== expectedType) { - throw new Error( - `Value for key: ${key} in payload was ${receivedType}, expected ${expectedType}`, - ); - } - }); -}; - -export default class PayloadDeserializer { - static createUserFromPayload(userPayload: any): User { - const basicUser = PayloadDeserializer.createBasicUserFromPayload( - userPayload, - ); - - return new User({ - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - customData: userPayload.custom_data, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - }); - } - - static createCurrentUserFromPayload( - userPayload: any, - apiInstance: Instance, - filesInstance: Instance, - cursorsInstance: Instance, - userStore: GlobalUserStore, - ): CurrentUser { - const basicUser = PayloadDeserializer.createBasicUserFromPayload( - userPayload, - ); - - return new CurrentUser({ - apiInstance, - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - cursorsInstance, - customData: userPayload.custom_data, - filesInstance, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - userStore, - }); - } - - static createRoomFromPayload(roomPayload: any): Room { - const requiredFieldsWithTypes: { [key: string]: string } = { - created_at: 'string', - created_by_id: 'string', - id: 'number', - name: 'string', - private: 'boolean', - updated_at: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, roomPayload); - - let memberUserIds: string[] = []; - - if (roomPayload.member_user_ids) { - memberUserIds = roomPayload.member_user_ids; - } - - return new Room({ - createdAt: roomPayload.created_at, - createdByUserId: roomPayload.created_by_id, - deletedAt: roomPayload.deleted_at, - id: roomPayload.id, - isPrivate: roomPayload.private, - name: roomPayload.name, - updatedAt: roomPayload.updated_at, - userIds: memberUserIds, - }); - } - - // This returns a PCBasicMessage mainly to signal that it needs to be enriched with - // information about its associated sender and the room it belongs to - static createBasicMessageFromPayload(messagePayload: any): BasicMessage { - const requiredFieldsWithTypes: { [key: string]: string } = { - created_at: 'string', - id: 'number', - room_id: 'number', - text: 'string', - updated_at: 'string', - user_id: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload( - requiredFieldsWithTypes, - messagePayload, - ); - - const attachment: Attachment | undefined = this.createAttachmentFromPayload( - messagePayload.attachment, - ); - - return { - attachment, - createdAt: messagePayload.created_at, - id: messagePayload.id, - roomId: messagePayload.room_id, - senderId: messagePayload.user_id, - text: messagePayload.text, - updatedAt: messagePayload.updated_at, - }; - } - - static createBasicCursorFromPayload(payload: any): BasicCursor { - const requiredFieldsWithTypes: { [key: string]: string } = { - cursor_type: 'number', - position: 'number', - room_id: 'number', - updated_at: 'string', - user_id: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - - return { - cursorType: payload.cursor_type, - position: payload.position, - roomId: payload.room_id, - updatedAt: payload.updated_at, - userId: payload.user_id, - }; - } - - static createPresencePayloadFromPayload(payload: any): PresencePayload { - const requiredFieldsWithTypes: { [key: string]: string } = { - state: 'string', - user_id: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - - const state = new PresenceState(payload.state); - - return { - lastSeenAt: payload.last_seen_at, - state, - userId: payload.user_id, - }; - } - - static createBasicUserFromPayload(payload: any): BasicUser { - const requiredFieldsWithTypes: { [key: string]: string } = { - created_at: 'string', - id: 'string', - updated_at: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - - return { - createdAt: payload.created_at, - id: payload.id, - updatedAt: payload.updated_at, - }; - } - - static createAttachmentFromPayload(payload: any): Attachment | undefined { - if (payload === undefined) { - return undefined; - } - - const requiredFieldsWithTypes: { [key: string]: string } = { - resource_link: 'string', - type: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - - const linkQueryParams = queryParamsFromFullUrl(payload.resource_link); - const fetchRequired = - linkQueryParams.chatkit_link !== undefined && - linkQueryParams.chatkit_link === 'true'; - - return { - fetchRequired, - link: payload.resource_link, - type: payload.type, - }; - } - - static createFetchedAttachmentFromPayload( - payload: any, - ): FetchedAttachment | undefined { - if (payload === undefined) { - return undefined; - } - - const requiredFieldsWithTypes: { [key: string]: string } = { - file: 'object', - resource_link: 'string', - ttl: 'number', - }; - - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - - const requiredFieldsWithTypesForFileField: { [key: string]: string } = { - bytes: 'number', - last_modified: 'number', - name: 'string', - }; - - checkPresenceAndTypeOfFieldsInPayload( - requiredFieldsWithTypesForFileField, - payload.file, - ); - - const file = payload.file; - const { bytes, name } = file; - - return { - file: { - bytes, - lastModified: file.last_modified, - name, - }, - link: payload.resource_link, - ttl: payload.ttl, - }; - } -} diff --git a/src/presence_payload.ts b/src/presence_payload.ts deleted file mode 100644 index c8708a9..0000000 --- a/src/presence_payload.ts +++ /dev/null @@ -1,9 +0,0 @@ -import PresenceState from './presence_state'; - -interface PresencePayload { - userId: string; - state: PresenceState; - lastSeenAt?: string; -} - -export default PresencePayload; diff --git a/src/presence_state.ts b/src/presence_state.ts deleted file mode 100644 index c867158..0000000 --- a/src/presence_state.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default class PresenceState { - stringValue: string; - - constructor(state: string) { - switch (state) { - case 'online': - this.stringValue = state; - break; - case 'offline': - this.stringValue = state; - break; - default: - this.stringValue = 'unknown'; - break; - } - } -} diff --git a/src/presence_subscription.ts b/src/presence_subscription.ts deleted file mode 100644 index 21576be..0000000 --- a/src/presence_subscription.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; - -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import PayloadDeserializer from './payload_deserializer'; -import RoomStore from './room_store'; -import User from './user'; - -export interface PresenceSubscriptionOptions { - apiInstance: Instance; - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; -} - -export default class PresenceSubscription { - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; - - private apiInstance: Instance; - - constructor(options: PresenceSubscriptionOptions) { - this.apiInstance = options.apiInstance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.delegate = options.delegate; - } - - handleEvent(event: SubscriptionEvent) { - const { body, eventId, headers } = event; - const { data } = body; - const eventName = body.event_name; - - this.apiInstance.logger.verbose( - `Received event type: ${eventName}, and data: ${data}`, - ); - - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'presence_update': - this.parsePresenceUpdatePayload(eventName, data, this.userStore); - break; - case 'join_room_presence_update': - this.parseJoinRoomPresenceUpdatePayload( - eventName, - data, - this.userStore, - ); - break; - default: - this.apiInstance.logger.verbose( - `Unsupported event type received: ${eventName}, and data: ${data}`, - ); - break; - } - } - - end() { - // TODO: Work out how to implement - } - - parseInitialStatePayload( - eventName: string, - data: any, - userStore: GlobalUserStore, - ) { - const userStatesPayload = data.user_states; - - if ( - userStatesPayload === undefined || - userStatesPayload.constructor !== Array - ) { - this.apiInstance.logger.debug( - `'user_stats' value missing from ${eventName} presence payload: ${data}`, - ); - // TODO: Do we want the error delegate? - // self.delegate?.error(error: error) - return; - } - - // TODO: It will never be undefined but might throw - this is semi-aspirational code - const userStates = userStatesPayload - .map((userStatePayload: any) => { - return PayloadDeserializer.createPresencePayloadFromPayload( - userStatePayload, - ); - }) - .filter((el: any) => el !== undefined); - - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - - this.userStore.handleInitialPresencePayloads(userStates, () => { - this.roomStore.rooms.forEach(room => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - this.apiInstance.logger.verbose(`Users updated in room ${room.name}`); - }); - }); - } - - parsePresenceUpdatePayload( - eventName: string, - data: any, - userStore: GlobalUserStore, - ) { - const presencePayload = PayloadDeserializer.createPresencePayloadFromPayload( - data, - ); - - userStore.user( - presencePayload.userId, - user => { - user.updatePresenceInfoIfAppropriate(presencePayload); - - switch (presencePayload.state.stringValue) { - case 'online': - if (this.delegate && this.delegate.userCameOnline) { - this.delegate.userCameOnline(user); - } - this.apiInstance.logger.verbose(`${user.id} came online`); - break; - case 'offline': - if (this.delegate && this.delegate.userWentOffline) { - this.delegate.userWentOffline(user); - } - this.apiInstance.logger.verbose(`${user.id} went offline`); - break; - case 'unknown': - // This should never be the case - this.apiInstance.logger.verbose( - `Somehow the presence state of user ${user.id} is unknown`, - ); - break; - } - - // TODO: Could check if any room is active to speed this up? Or keep a better - // map of user_ids to rooms - this.roomStore.rooms.forEach(room => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - return; - } - - if (room.userIds.indexOf(user.id) > -1) { - switch (presencePayload.state.stringValue) { - case 'online': - if ( - room.subscription.delegate && - room.subscription.delegate.userCameOnlineInRoom - ) { - room.subscription.delegate.userCameOnlineInRoom(user); - } - break; - case 'offline': - if ( - room.subscription.delegate && - room.subscription.delegate.userWentOfflineInRoom - ) { - room.subscription.delegate.userWentOfflineInRoom(user); - } - break; - default: - break; - } - } - }); - }, - error => { - this.apiInstance.logger.debug( - `Error fetching user information for user with id ${ - presencePayload.userId - }:`, - error, - ); - return; - }, - ); - } - - // TODO: So much duplication - parseJoinRoomPresenceUpdatePayload( - eventName: string, - data: any, - userStore: GlobalUserStore, - ) { - const userStatesPayload = data.user_states; - - if ( - userStatesPayload === undefined || - userStatesPayload.constructor !== Array - ) { - this.apiInstance.logger.debug( - `'user_stats' value missing from ${eventName} presence payload: ${data}`, - ); - // TODO: Delegate question again - // self.delegate?.error(error: error) - return; - } - - // TODO: It will never be undefined but might throw - this is semi-aspirational code - const userStates = userStatesPayload - .map((userStatePayload: any) => { - return PayloadDeserializer.createPresencePayloadFromPayload( - userStatePayload, - ); - }) - .filter((el: any) => el !== undefined); - - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - - this.userStore.handleInitialPresencePayloads(userStates, () => { - this.roomStore.rooms.forEach(room => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - - this.apiInstance.logger.verbose(`Users updated in room ${room.name}`); - }); - }); - } -} diff --git a/src/room.ts b/src/room.ts deleted file mode 100644 index c862ae4..0000000 --- a/src/room.ts +++ /dev/null @@ -1,49 +0,0 @@ -import CursorSubscription from './cursor_subscription'; -import RoomSubscription from './room_subscription'; -import RoomUserStore from './room_user_store'; - -export interface RoomOptions { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds?: string[]; -} - -export default class Room { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds: string[]; - - userStore: RoomUserStore; - subscription?: RoomSubscription; - cursorSubscription?: CursorSubscription; - - constructor(options: RoomOptions) { - this.id = options.id; - this.name = options.name; - this.isPrivate = options.isPrivate; - this.createdByUserId = options.createdByUserId; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.deletedAt = options.deletedAt; - this.userIds = options.userIds || []; - this.userStore = new RoomUserStore(); - } - - updateWithPropertiesOfRoom(room: Room) { - this.name = room.name; - this.isPrivate = room.isPrivate; - this.updatedAt = room.updatedAt; - this.deletedAt = room.deletedAt; - this.userIds = room.userIds; - } -} diff --git a/src/room_delegate.ts b/src/room_delegate.ts deleted file mode 100644 index d9b416d..0000000 --- a/src/room_delegate.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Cursor from './cursor'; -import Message from './message'; -import User from './user'; - -interface RoomDelegate { - newMessage?: (message: Message) => void; - userStartedTyping?: (user: User) => void; - userStoppedTyping?: (user: User) => void; - - userJoined?: (user: User) => void; - userLeft?: (user: User) => void; - - userCameOnlineInRoom?: (user: User) => void; - userWentOfflineInRoom?: (user: User) => void; - - // TODO: This seems like it could instead be `userListUpdated`, or something similar? - usersUpdated?: () => void; - - error?: (error: any) => void; - cursorSet?: (cursor: Cursor) => void; -} - -export default RoomDelegate; diff --git a/src/room_store.ts b/src/room_store.ts deleted file mode 100644 index 319600f..0000000 --- a/src/room_store.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Instance } from 'pusher-platform'; - -import PayloadDeserializer from './payload_deserializer'; -import Room from './room'; - -export interface RoomStoreOptions { - rooms: Room[]; - apiInstance: Instance; -} - -export default class RoomStore { - rooms: Room[]; - apiInstance: Instance; - - constructor(options: RoomStoreOptions) { - this.rooms = options.rooms; - this.apiInstance = options.apiInstance; - } - - room( - id: number, - onSuccess: (room: Room) => void, - onError: (error: Error) => void, - ) { - this.findOrGetRoom(id, onSuccess, onError); - } - - addOrMerge(room: Room): Room { - const existingRoom = this.rooms.find(el => el.id === room.id); - - if (existingRoom) { - existingRoom.updateWithPropertiesOfRoom(room); - return existingRoom; - } else { - this.rooms.push(room); - return room; - } - } - - remove(id: number): Room | undefined { - const indexOfRoom = this.rooms.findIndex(el => el.id === id); - if (indexOfRoom === -1) { - return undefined; - } - - const room = this.rooms[indexOfRoom]; - this.rooms.splice(indexOfRoom, 1); - return room; - } - - findOrGetRoom( - id: number, - onSuccess: (room: Room) => void, - onError: (error: Error) => void, - ) { - const room = this.rooms.find(el => el.id === id); - if (room) { - onSuccess(room); - } else { - this.getRoom(id, onSuccess, onError); - } - } - - getRoom( - id: number, - onSuccess: (room: Room) => void, - onError: (error: Error) => void, - ) { - this.apiInstance - .request({ - method: 'GET', - path: `/rooms/${id}`, - }) - .then((res: any) => { - const roomPayload = JSON.parse(res); - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - onSuccess(room); - }) - .catch((error: any) => { - this.apiInstance.logger.debug(`Error fetching room ${id}:`, error); - onError(error); - }); - } -} diff --git a/src/room_subscription.ts b/src/room_subscription.ts deleted file mode 100644 index ca2511c..0000000 --- a/src/room_subscription.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Instance, Logger, SubscriptionEvent } from 'pusher-platform'; - -import BasicMessageEnricher from './basic_message_enricher'; -import PayloadDeserializer from './payload_deserializer'; -import RoomDelegate from './room_delegate'; -import User from './user'; - -export interface RoomSubscriptionOptions { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; -} - -export default class RoomSubscription { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; - - constructor(options: RoomSubscriptionOptions) { - this.delegate = options.delegate; - this.basicMessageEnricher = options.basicMessageEnricher; - this.logger = options.logger; - } - - handleEvent(event: SubscriptionEvent) { - const { body, eventId, headers } = event; - const { data } = body; - const eventName = body.event_name; - - if (eventName !== 'new_message') { - this.logger.verbose( - `Room subscription received event with type ${eventName}, when 'new_message' was expected`, - ); - return; - } - - this.logger.verbose(`Received event name: ${eventName}, and data:`, data); - - const basicMessage = PayloadDeserializer.createBasicMessageFromPayload( - data, - ); - - this.basicMessageEnricher.enrich( - basicMessage, - message => { - this.logger.verbose(`Room received new message: ${message.text}`); - - if (this.delegate && this.delegate.newMessage) { - this.delegate.newMessage(message); - } - }, - error => { - this.logger.debug('Error receiving new message:', error); - }, - ); - } -} diff --git a/src/room_user_store.ts b/src/room_user_store.ts deleted file mode 100644 index b125c4f..0000000 --- a/src/room_user_store.ts +++ /dev/null @@ -1,18 +0,0 @@ -import User from './user'; -import UserStoreCore from './user_store_core'; - -export default class RoomUserStore { - private userStoreCore: UserStoreCore; - - constructor(userStoreCore = new UserStoreCore()) { - this.userStoreCore = userStoreCore; - } - - addOrMerge(user: User): User { - return this.userStoreCore.addOrMerge(user); - } - - remove(id: string): User | undefined { - return this.userStoreCore.remove(id); - } -} diff --git a/src/token_provider.ts b/src/token_provider.ts deleted file mode 100644 index 136c44c..0000000 --- a/src/token_provider.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - sendRawRequest, - TokenProvider as PlatformTokenProvider, -} from 'pusher-platform'; - -import { mergeQueryParamsIntoUrl, urlEncode } from './utils'; - -export interface TokenProviderAuthContextOptions { - queryParams?: TokenProviderAuthContextQueryParams; - headers?: TokenProviderAuthContextHeaders; -} - -export type TokenProviderAuthContextHeaders = { - [key: string]: string; -}; - -export type TokenProviderAuthContextQueryParams = { - [key: string]: string; -}; - -export interface TokenProviderOptions { - authContext?: TokenProviderAuthContextOptions; - url: string; -} - -export default class TokenProvider implements PlatformTokenProvider { - authContext?: TokenProviderAuthContextOptions; - url: string; - userId?: string; - - cachedAccessToken?: string; - cachedTokenExpiresAt?: number; - - constructor(options: TokenProviderOptions) { - this.authContext = options.authContext || {}; - this.url = options.url; - } - - get cacheIsStale() { - if (this.cachedAccessToken && this.cachedTokenExpiresAt) { - return this.unixTimeNow() > this.cachedTokenExpiresAt; - } - return true; - } - - fetchToken(tokenParams?: any): Promise { - if (this.cacheIsStale) { - return this.makeAuthRequest().then(responseBody => { - const { access_token, expires_in } = responseBody; - this.cache(access_token, expires_in); - return access_token; - }); - } - return new Promise((resolve, reject) => { - resolve(this.cachedAccessToken); - }); - } - - clearToken(token?: string) { - this.cachedAccessToken = undefined; - this.cachedTokenExpiresAt = undefined; - } - - makeAuthRequest(): Promise { - let url; - - const authRequestQueryParams = (this.authContext || {}).queryParams || {}; - - if (this.userId === undefined) { - url = mergeQueryParamsIntoUrl(this.url, authRequestQueryParams); - } else { - const authContextWithUserId = { - user_id: this.userId, - ...authRequestQueryParams, - }; - url = mergeQueryParamsIntoUrl(this.url, authContextWithUserId); - } - - const authRequestHeaders = (this.authContext || {}).headers || {}; - - const headers = { - ['Content-Type']: 'application/x-www-form-urlencoded', - ...authRequestHeaders, - }; - - const body = urlEncode({ grant_type: 'client_credentials' }); - - return sendRawRequest({ - body, - headers, - method: 'POST', - url, - }).then((res: any) => { - return JSON.parse(res); - }); - } - - private cache(accessToken: string, expiresIn: number) { - this.cachedAccessToken = accessToken; - this.cachedTokenExpiresAt = this.unixTimeNow() + expiresIn; - } - - private unixTimeNow(): number { - return Math.floor(Date.now() / 1000); - } -} diff --git a/src/user.ts b/src/user.ts deleted file mode 100644 index b71212f..0000000 --- a/src/user.ts +++ /dev/null @@ -1,48 +0,0 @@ -import PresencePayload from './presence_payload'; -import PresenceState from './presence_state'; - -export interface UserOptions { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; -} - -export default class User { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; - presenceState: PresenceState; - lastSeenAt?: string; - - constructor(options: UserOptions) { - this.id = options.id; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.presenceState = new PresenceState('unknown'); - } - - updateWithPropertiesOfUser(user: User) { - if (user.presenceState.stringValue !== 'unknown') { - this.presenceState = user.presenceState; - this.lastSeenAt = user.lastSeenAt; - } - - return this; - } - - updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload) { - if (newInfoPayload.state.stringValue !== 'unknown') { - this.presenceState = newInfoPayload.state; - this.lastSeenAt = newInfoPayload.lastSeenAt; - } - } -} diff --git a/src/user_store_core.ts b/src/user_store_core.ts deleted file mode 100644 index d34a1c2..0000000 --- a/src/user_store_core.ts +++ /dev/null @@ -1,36 +0,0 @@ -import User from './user'; - -export default class UserStoreCore { - private users: User[]; - - constructor(users = new Array()) { - this.users = users; - } - - addOrMerge(user: User): User { - const existingUser = this.users.find(el => el.id === user.id); - - if (existingUser) { - existingUser.updateWithPropertiesOfUser(user); - return existingUser; - } else { - this.users.push(user); - return user; - } - } - - remove(id: string): User | undefined { - const indexOfUser = this.users.findIndex(el => el.id === id); - if (indexOfUser === -1) { - return undefined; - } - - const user = this.users[indexOfUser]; - this.users.splice(indexOfUser, 1); - return user; - } - - find(id: string): User | undefined { - return this.users.find(el => el.id === id); - } -} diff --git a/src/user_subscription.ts b/src/user_subscription.ts deleted file mode 100644 index a6989df..0000000 --- a/src/user_subscription.ts +++ /dev/null @@ -1,773 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; - -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -import GlobalUserStore from './global_user_store'; -import PayloadDeserializer from './payload_deserializer'; -import Room from './room'; -import User from './user'; - -import { TYPING_REQ_TTL } from './constants'; -import { allPromisesSettled } from './utils'; - -export interface UserSubscriptionOptions { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; -} - -export default class UserSubscription { - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; - currentUser?: CurrentUser; - - private apiInstance: Instance; - private filesInstance: Instance; - private cursorsInstance: Instance; - private typingTimers: { [roomId: number]: { [userId: string]: number } } = {}; - - constructor(options: UserSubscriptionOptions) { - this.apiInstance = options.apiInstance; - this.filesInstance = options.filesInstance; - this.cursorsInstance = options.cursorsInstance; - this.userStore = options.userStore; - this.delegate = options.delegate; - this.connectCompletionHandlers = [options.connectCompletionHandler]; - } - - handleEvent(event: SubscriptionEvent) { - const { body, eventId, headers } = event; - const { data } = body; - const eventName = body.event_name; - - this.apiInstance.logger.verbose( - `Received event name: ${eventName}, and data: ${data}`, - ); - - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'added_to_room': - this.parseAddedToRoomPayload(eventName, data); - break; - case 'removed_from_room': - this.parseRemovedFromRoomPayload(eventName, data); - break; - case 'room_updated': - this.parseRoomUpdatedPayload(eventName, data); - break; - case 'room_deleted': - this.parseRoomDeletedPayload(eventName, data); - break; - case 'user_joined': - this.parseUserJoinedPayload(eventName, data); - break; - case 'user_left': - this.parseUserLeftPayload(eventName, data); - break; - case 'typing_start': // 'is_typing' - // Treating like an is_typing event for now as an experiment - this.parseIsTypingPayload(eventName, data, data.user_id); - break; - case 'typing_stop': - // Ignored for now, using typing_start in lieu of is_typing - // this.parseTypingStopPayload(eventName, data, data.user_id); - break; - } - } - - callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error) { - this.connectCompletionHandlers.forEach(completionHandler => { - completionHandler(currentUser, error); - }); - } - - parseInitialStatePayload( - eventName: string, - data: any, - userStore: GlobalUserStore, - ) { - const roomsPayload = data.rooms; - const userPayload = data.current_user; - - const receivedCurrentUser = PayloadDeserializer.createCurrentUserFromPayload( - userPayload, - this.apiInstance, - this.filesInstance, - this.cursorsInstance, - this.userStore, - ); - - const wasExistingCurrentUser = this.currentUser !== undefined; - - // If the currentUser property is already set then the assumption is that there was - // already a user subscription and so instead of setting the property to a new - // CurrentUser, we update the existing one to have the most up-to-date state - if (this.currentUser) { - this.currentUser.updateWithPropertiesOf(receivedCurrentUser); - } else { - this.currentUser = receivedCurrentUser; - } - - const receivedRoomsConstructor = roomsPayload.constructor; - - if (receivedRoomsConstructor !== Array) { - throw TypeError( - '`rooms` key of initial_state payload was of type `${receivedRoomsConstructor}`, expected `Array`', - ); - } - - if (roomsPayload.length === 0) { - this.currentUser.setupPresenceSubscription(this.delegate); - this.callConnectCompletionHandlers(this.currentUser); - return; - } - - const combinedRoomUserIds = new Set([]); - const roomsFromConnection: Room[] = []; - - roomsPayload.forEach((roomPayload: any) => { - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - - room.userIds.forEach(userId => { - combinedRoomUserIds.add(userId); - }); - roomsFromConnection.push(room); - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.addOrMerge(room); - }); - - this.callConnectCompletionHandlers(this.currentUser); - this.fetchInitialUserInformationForUserIds( - combinedRoomUserIds, - this.currentUser, - ); - - if (wasExistingCurrentUser) { - this.reconcileExistingRoomStoreWithRoomsReceivedOnConnection( - roomsFromConnection, - ); - } - } - - fetchInitialUserInformationForUserIds( - userIds: Set, - currentUser: CurrentUser, - ) { - const userIdsArray: string[] = Array.from(userIds.values()); - - this.userStore.initialFetchOfUsersWithIds( - userIdsArray, - users => { - const combinedRoomUsersPromises = new Array>(); - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.rooms.forEach(room => { - const roomPromise = new Promise((roomResolve, roomReject) => { - const roomUsersPromises = new Array>(); - - room.userIds.forEach(userId => { - const userPromise = new Promise( - (userResolve, userReject) => { - this.userStore.user( - userId, - user => { - room.userStore.addOrMerge(user); - userResolve(); - }, - error => { - this.apiInstance.logger.verbose( - `Unable to fetch information about user ${userId}`, - ); - userReject(); - }, - ); - }, - ); - roomUsersPromises.push(userPromise); - }); - - allPromisesSettled(roomUsersPromises).then(() => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - - this.apiInstance.logger.verbose( - `Users updated in room ${room.name}"`, - ); - roomResolve(); - }); - }); - - combinedRoomUsersPromises.push(roomPromise); - }); - - allPromisesSettled(combinedRoomUsersPromises).then(() => { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.setupPresenceSubscription(this.delegate); - }); - }, - error => { - this.apiInstance.logger.debug( - `Unable to fetch user information after successful connection: ${error}`, - ); - return; - }, - ); - } - - reconcileExistingRoomStoreWithRoomsReceivedOnConnection( - roomsFromConnection: Room[], - ) { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property of UserSubscription unset after successful connection', - ); - return; - } - - const roomStoreRooms = this.currentUser.roomStore.rooms; - const mostRecentConnectionRoomsSet = new Set(roomsFromConnection); - - const noLongerAMemberOfRooms = roomStoreRooms.filter( - room => !mostRecentConnectionRoomsSet.has(room), - ); - - noLongerAMemberOfRooms.forEach(room => { - // TODO: Not sure if this is the best way of communicating that while the subscription - // was closed there was an event that meant that the current user is no longer a - // member of a given room - - if (this.delegate && this.delegate.removedFromRoom) { - this.delegate.removedFromRoom(room); - } - }); - } - - parseAddedToRoomPayload(eventName: string, data: any) { - const roomPayload = data.room; - - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose( - `\`room\` key missing or invalid in \`added_to_room\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - const roomAdded = this.currentUser.roomStore.addOrMerge(room); - - if (this.delegate && this.delegate.addedToRoom) { - this.delegate.addedToRoom(room); - } - - this.apiInstance.logger.verbose(`Added to room: ${room.name}`); - - const roomUsersPromises = new Array>(); - - roomAdded.userIds.forEach(userId => { - const userPromise = new Promise((resolve, reject) => { - this.userStore.user( - userId, - user => { - this.apiInstance.logger.verbose( - `Added user id ${userId} to room ${room.name}`, - ); - room.userStore.addOrMerge(user); - resolve(); - }, - error => { - this.apiInstance.logger.debug( - `Unable to add user with id ${userId} to room ${ - room.name - }: ${error}`, - ); - reject(); - }, - ); - }); - roomUsersPromises.push(userPromise); - }); - - allPromisesSettled(roomUsersPromises).then(() => { - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.usersUpdated - ) { - room.subscription.delegate.usersUpdated(); - } - } - - this.apiInstance.logger.verbose(`Users updated in room ${room.name}`); - }); - } - - parseRemovedFromRoomPayload(eventName: string, data: any) { - const roomId = data.room_id; - - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose( - `\`room_id\` key missing or invalid in \`removed_from_room\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - const roomRemoved = this.currentUser.roomStore.remove(roomId); - - if (roomRemoved) { - if (this.delegate && this.delegate.removedFromRoom) { - this.delegate.removedFromRoom(roomRemoved); - } - this.apiInstance.logger.verbose(`Removed from room: ${roomRemoved.name}`); - } else { - this.apiInstance.logger.verbose( - `Received \`removed_from_room\` API event but room with ID ${roomId} not found in local store of joined rooms`, - ); - return; - } - } - - parseRoomUpdatedPayload(eventName: string, data: any) { - const roomPayload = data.room; - - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose( - `\`room\` key missing or invalid in \`room_updated\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - const room = PayloadDeserializer.createRoomFromPayload(roomPayload); - - this.currentUser.roomStore.room( - room.id, - roomToUpdate => { - roomToUpdate.updateWithPropertiesOfRoom(room); - - if (this.delegate && this.delegate.roomUpdated) { - this.delegate.roomUpdated(roomToUpdate); - } - - this.apiInstance.logger.verbose(`Room updated: ${room.name}`); - }, - error => { - this.apiInstance.logger.debug(`Error updating room ${room.id}:`, error); - }, - ); - } - - parseRoomDeletedPayload(eventName: string, data: any) { - const roomId = data.room_id; - - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose( - `\`room_id\` key missing or invalid in \`room_deleted\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - const deletedRoom = this.currentUser.roomStore.remove(roomId); - - if (deletedRoom) { - if (this.delegate && this.delegate.roomDeleted) { - this.delegate.roomDeleted(deletedRoom); - } - - this.apiInstance.logger.verbose(`Room deleted: ${deletedRoom.name}`); - } else { - this.apiInstance.logger.verbose( - `Received \`room_deleted\` API event but room with ID ${roomId} not found in local store of joined rooms`, - ); - return; - } - } - - parseUserJoinedPayload(eventName: string, data: any) { - const roomId = data.room_id; - - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose( - `\`room_id\` key missing or invalid in \`user_joined\` payload: ${data}`, - ); - return; - } - - const userId = data.user_id; - - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose( - `\`user_id\` key missing or invalid in \`user_joined\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.room( - roomId, - room => { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.userStore.user( - userId, - user => { - const addedOrMergedUser = room.userStore.addOrMerge(user); - if (room.userIds.indexOf(addedOrMergedUser.id) === -1) { - room.userIds.push(addedOrMergedUser.id); - } - - if (this.delegate && this.delegate.userJoinedRoom) { - this.delegate.userJoinedRoom(room, addedOrMergedUser); - } - - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.userJoined - ) { - room.subscription.delegate.userJoined(addedOrMergedUser); - } - } - - this.apiInstance.logger.verbose( - `User ${user.id} joined room: ${room.name}`, - ); - }, - error => { - this.apiInstance.logger.verbose( - `Error fetching user ${userId}:`, - error, - ); - // TODO: Delegate question again - // strongSelf.delegate.error(error: err!) - return; - }, - ); - }, - error => { - this.apiInstance.logger.verbose( - `User with id ${userId} joined room with id ${roomId} but no information about the room could be retrieved. Error was: ${error}`, - ); - // self.delegate.error(error: err!) - return; - }, - ); - } - - parseUserLeftPayload(eventName: string, data: any) { - const roomId = data.room_id; - - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose( - `\`room_id\` key missing or invalid in \`user_left\` payload: ${data}`, - ); - return; - } - - const userId = data.user_id; - - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose( - `\`user_id\` key missing or invalid in \`user_left\` payload: ${data}`, - ); - return; - } - - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.room( - roomId, - room => { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.userStore.user( - userId, - user => { - const roomUserIdIndex = room.userIds.indexOf(user.id); - - if (roomUserIdIndex > -1) { - room.userIds.splice(roomUserIdIndex, 1); - } - - room.userStore.remove(user.id); - - if (this.delegate && this.delegate.userLeftRoom) { - this.delegate.userLeftRoom(room, user); - } - - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.userLeft - ) { - room.subscription.delegate.userLeft(user); - } - } - - this.apiInstance.logger.verbose( - `User ${user.id} left room ${room.name}`, - ); - }, - error => { - this.apiInstance.logger.verbose( - `User with id ${userId} left room with id ${roomId} but no information about the user could be retrieved. Error was: ${error}`, - ); - // strongSelf.delegate.error(error: err!) - return; - }, - ); - }, - error => { - this.apiInstance.logger.verbose( - `User with id ${userId} joined room with id ${roomId} but no information about the room could be retrieved. Error was: ${error}`, - ); - // self.delegate.error(error: err!) - return; - }, - ); - } - - parseIsTypingPayload(eventName: string, data: any, userId: string) { - const roomId = data.room_id; - - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose( - `\`room_id\` key missing or invalid in \`typing_start\` payload: ${data}`, - ); - return; - } - - if (!this.typingTimers[roomId]) { - this.typingTimers[roomId] = {}; - } - if (this.typingTimers[roomId][userId]) { - clearTimeout(this.typingTimers[roomId][userId]); - } else { - this.startedTyping(roomId, userId); - } - this.typingTimers[roomId][userId] = setTimeout(() => { - this.stoppedTyping(roomId, userId); - delete this.typingTimers[roomId][userId]; - }, TYPING_REQ_TTL); - } - - private startedTyping(roomId: number, userId: string) { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.room( - roomId, - room => { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.userStore.user( - userId, - user => { - if (this.delegate && this.delegate.userStartedTyping) { - this.delegate.userStartedTyping(room, user); - } - - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.userStartedTyping - ) { - room.subscription.delegate.userStartedTyping(user); - } - } - - this.apiInstance.logger.verbose( - `User ${user.id} started typing in room ${room.name}`, - ); - }, - error => { - this.apiInstance.logger.verbose( - `Error fetching information for user ${userId}:`, - error, - ); - // strongSelf.delegate.error(error: err!) - return; - }, - ); - }, - error => { - this.apiInstance.logger.verbose( - `Error fetching information for room ${roomId}:`, - error, - ); - // self.delegate.error(error: err!) - return; - }, - ); - } - - private stoppedTyping(roomId: number, userId: string) { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.roomStore.room( - roomId, - room => { - if (!this.currentUser) { - this.apiInstance.logger.verbose( - 'currentUser property not set on UserSubscription', - ); - return; - } - - this.currentUser.userStore.user( - userId, - user => { - if (this.delegate && this.delegate.userStoppedTyping) { - this.delegate.userStoppedTyping(room, user); - } - - if (room.subscription === undefined) { - this.apiInstance.logger.verbose( - `Room ${room.name} has no subscription object set`, - ); - } else { - if ( - room.subscription.delegate && - room.subscription.delegate.userStoppedTyping - ) { - room.subscription.delegate.userStoppedTyping(user); - } - } - - this.apiInstance.logger.verbose( - `User ${user.id} stopped typing in room ${room.name}`, - ); - }, - error => { - this.apiInstance.logger.debug( - `Error fetching information for user ${userId}:`, - error, - ); - // strongSelf.delegate.error(error: err!) - return; - }, - ); - }, - error => { - this.apiInstance.logger.debug( - `Error fetching information for room ${roomId}:`, - error, - ); - // self.delegate.error(error: err!) - return; - }, - ); - } -} diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index 6c97be9..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,80 +0,0 @@ -export function urlEncode(data: any) { - return Object.keys(data) - .filter(key => data[key] !== undefined) - .map(key => `${key}=${encodeURIComponent(data[key])}`) - .join('&'); -} - -export function queryString(data: any): string { - const encodedData = urlEncode(data); - return encodedData ? `?${encodedData}` : ''; -} - -export function queryParamsFromFullUrl(url: string): any { - if (url.indexOf('?') === -1) { - return {}; - } - - const splitUrl = url.split('?'); - const queryStr = splitUrl.slice(1).join('&'); - - return queryParamObject(queryStr); -} - -function querylessUrlAndQueryObjectFromFullUrl(urlString: string): any { - if (urlString.indexOf('?') === -1) { - return { - queryObject: {}, - querylessUrl: urlString, - }; - } - - const splitUrl = urlString.split('?'); - const querylessUrl = splitUrl[0]; - const queryStr = splitUrl.slice(1).join('&'); - - return { - queryObject: queryParamObject(queryStr), - querylessUrl, - }; -} - -function queryParamObject(queryParamString: string): any { - return queryParamString - .split('&') - .map(str => { - const [key, value] = str.split('='); - return { [key]: decodeURI(value) }; - }) - .reduce((prev, curr) => Object.assign(prev, curr)); -} - -export function mergeQueryParamsIntoUrl( - urlString: string, - queryParams: any, -): string { - const { querylessUrl, queryObject } = querylessUrlAndQueryObjectFromFullUrl( - urlString, - ); - const fullQueryString = queryString(Object.assign(queryObject, queryParams)); - return `${querylessUrl}${fullQueryString}`; -} - -export function allPromisesSettled( - promises: Array>, -): Promise { - return Promise.all( - promises.map((p: Promise) => - Promise.resolve(p).then( - v => ({ - state: 'fulfilled', - value: v, - }), - r => ({ - reason: r, - state: 'rejected', - }), - ), - ), - ); -} diff --git a/tests/package.json b/tests/package.json deleted file mode 100644 index cc194f5..0000000 --- a/tests/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "devDependencies": { - "babel-core": "^6.26.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0", - "babel-preset-env": "^1.6.1", - "babelify": "^8.0.0", - "browserify": "^15.2.0", - "faucet": "^0.0.1", - "pusher-chatkit-server": "^0.9.1", - "ramda": "^0.25.0", - "snazzy": "^7.0.0", - "standard": "^10.0.3", - "tape": "^4.8.0", - "tape-run": "^3.0.2" - }, - "scripts": { - "lint": "standard --verbose | snazzy", - "test": "browserify main.js -t babelify | tape-run | faucet", - "lint:test": "clear && yarn lint && clear && yarn test" - }, - "babel": { - "presets": [ - "env" - ], - "plugins": [ - "transform-object-rest-spread" - ] - } -} diff --git a/tests/yarn.lock b/tests/yarn.lock deleted file mode 100644 index 10aac33..0000000 --- a/tests/yarn.lock +++ /dev/null @@ -1,3760 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@browserify/acorn5-object-spread@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@browserify/acorn5-object-spread/-/acorn5-object-spread-5.0.1.tgz#92e9b37f97beac9ec429a3cc479ded380297540c" - dependencies: - acorn "^5.2.1" - -"@juliangruber/tap-finished@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@juliangruber/tap-finished/-/tap-finished-0.0.2.tgz#a9aad63d5e4425ff8a6d9a6a94ab287a1b595dbe" - dependencies: - once "^1.3.3" - tap-parser "~0.2.0" - through "~2.3.4" - -"@types/node@^7.0.18": - version "7.0.52" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716" - -JSONStream@^1.0.3: - version "1.3.2" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - -acorn@^5.2.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" - -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - -ajv@^4.7.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.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-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - -array-filter@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - -array-map@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" - -array-reduce@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array.prototype.find@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - -asn1.js@^4.0.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - dependencies: - util "0.10.3" - -astw@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/astw/-/astw-2.2.0.tgz#7bd41784d32493987aeb239b6b4e1c57a873b917" - dependencies: - acorn "^4.0.3" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -babel-code-frame@^6.16.0, babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-core@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.7" - slash "^1.0.0" - source-map "^0.5.6" - -babel-generator@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.6" - trim-right "^1.0.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-to-generator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.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" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-preset-env@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^2.1.2" - invariant "^2.2.2" - semver "^5.3.0" - -babel-register@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.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" - -babel-template@^6.24.1, babel-template@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - dependencies: - babel-runtime "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - lodash "^4.17.4" - -babel-traverse@^6.24.1, babel-traverse@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babelify@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/babelify/-/babelify-8.0.0.tgz#6f60f5f062bfe7695754ef2403b842014a580ed3" - -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -base64-js@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" - -base64url@2.0.0, base64url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - -body-parser@^1.17.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" - on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - -brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browser-launcher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-launcher/-/browser-launcher-1.0.0.tgz#0cf0ff1ecdcb7516c8f973bf82eb6f3bf929ce97" - dependencies: - headless "~0.1.3" - merge "~1.0.0" - minimist "0.0.5" - mkdirp "~0.3.3" - plist "0.2.1" - xtend "^4.0.0" - -browser-pack@^6.0.1: - version "6.0.3" - resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.3.tgz#91ca96518583ef580ab063a309de62e407767a39" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.8.0" - defined "^1.0.0" - safe-buffer "^5.1.1" - through2 "^2.0.0" - umd "^3.0.0" - -browser-resolve@^1.11.0, browser-resolve@^1.7.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" - -browser-run@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/browser-run/-/browser-run-4.1.1.tgz#f90b35a12c9d2a8b0bd5ce139680409e8c00ba4a" - dependencies: - browser-launcher "^1.0.0" - duplexer "^0.1.1" - ecstatic "^2.0.0" - electron-stream "^5.1.1" - enstore "^1.0.1" - html-inject-script "^1.1.0" - optimist "^0.6.1" - phantomjs-stream "^1.1.1" - server-destroy "^1.0.1" - source-map-support "^0.4.0" - through "^2.3.8" - xhr-write-stream "^0.1.2" - xtend "^4.0.1" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - dependencies: - pako "~1.0.5" - -browserify@^15.2.0: - version "15.2.0" - resolved "https://registry.yarnpkg.com/browserify/-/browserify-15.2.0.tgz#1e121ba1fa72cf9fd2d8df002f8674b68b45df89" - dependencies: - JSONStream "^1.0.3" - assert "^1.4.0" - browser-pack "^6.0.1" - browser-resolve "^1.11.0" - browserify-zlib "~0.2.0" - buffer "^5.0.2" - cached-path-relative "^1.0.0" - concat-stream "~1.5.1" - console-browserify "^1.1.0" - constants-browserify "~1.0.0" - crypto-browserify "^3.0.0" - defined "^1.0.0" - deps-sort "^2.0.0" - domain-browser "~1.1.0" - duplexer2 "~0.1.2" - events "~1.1.0" - glob "^7.1.0" - has "^1.0.0" - htmlescape "^1.1.0" - https-browserify "^1.0.0" - inherits "~2.0.1" - insert-module-globals "^7.0.0" - labeled-stream-splicer "^2.0.0" - mkdirp "^0.5.0" - module-deps "^5.0.1" - os-browserify "~0.3.0" - parents "^1.0.1" - path-browserify "~0.0.0" - process "~0.11.0" - punycode "^1.3.2" - querystring-es3 "~0.2.0" - read-only-stream "^2.0.0" - readable-stream "^2.0.2" - resolve "^1.1.4" - shasum "^1.0.0" - shell-quote "^1.6.1" - stream-browserify "^2.0.0" - stream-http "^2.0.0" - string_decoder "~1.0.0" - subarg "^1.0.0" - syntax-error "^1.1.1" - through2 "^2.0.0" - timers-browserify "^1.0.1" - tty-browserify "~0.0.0" - url "~0.11.0" - util "~0.10.1" - vm-browserify "~0.0.1" - xtend "^4.0.0" - -browserslist@^2.1.2: - version "2.11.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" - dependencies: - caniuse-lite "^1.0.30000792" - electron-to-chromium "^1.3.30" - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer@^5.0.2: - version "5.0.8" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -builtin-modules@^1.0.0, builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - -cached-path-relative@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - -caniuse-lite@^1.0.30000792: - version "1.0.30000792" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000792.tgz#d0cea981f8118f3961471afbb43c9a1e5bbf0332" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chalk@^1.0.0, chalk@^1.1.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" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - -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-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -combine-source-map@~0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - -combine-source-map@~0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - -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.6.0, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-stream@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-0.1.1.tgz#d7f4e278b90cfc4f0f3ef77fe4c03b40eb3f7900" - -concat-stream@~1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - dependencies: - date-now "^0.1.4" - -constants-browserify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - -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.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - -convert-source-map@~1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" - -core-js@^2.4.0, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - ripemd160 "^2.0.0" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - -crypto-browserify@^3.0.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - -cssauron@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" - dependencies: - through X.X.X - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" - -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - -debug-log@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" - -debug@2.6.9, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.1, debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -deep-equal@~0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" - -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - -defined@0.0.0, defined@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" - -defined@^1.0.0, defined@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -deglob@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.0.tgz#4d44abe16ef32c779b4972bd141a80325029a14a" - dependencies: - find-root "^1.0.0" - glob "^7.0.5" - ignore "^3.0.9" - pkg-config "^1.1.0" - run-parallel "^1.1.2" - uniq "^1.0.1" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - -depd@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - -deps-sort@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" - dependencies: - JSONStream "^1.0.3" - shasum "^1.0.0" - subarg "^1.0.0" - through2 "^2.0.0" - -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -detective@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.0.2.tgz#84ec2e1c581e74211e2ae4ffce1edf52c3263f84" - dependencies: - "@browserify/acorn5-object-spread" "^5.0.1" - acorn "^5.2.1" - defined "^1.0.0" - -dezalgo@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - dependencies: - asap "^2.0.0" - wrappy "1" - -diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -doctrine@1.5.0, doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - dependencies: - esutils "^2.0.2" - -domain-browser@~1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" - -duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - -duplexer2@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - dependencies: - readable-stream "~1.1.9" - -duplexer@^0.1.1, duplexer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - -duplexer@~0.0.2: - version "0.0.4" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.0.4.tgz#afcb7f1f8b8d74f820726171d5d64ac9e4a8ff20" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.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" - dependencies: - base64url "^2.0.0" - safe-buffer "^5.0.1" - -ecstatic@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-2.2.1.tgz#b5087fad439dd9dd49d31e18131454817fe87769" - dependencies: - he "^1.1.1" - mime "^1.2.11" - minimist "^1.1.0" - url-join "^2.0.2" - -ecstatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.1.1.tgz#2564aa9dde84179dcaf926a9e6d12df13a0b666d" - dependencies: - he "^1.1.1" - mime "^1.4.1" - minimist "^1.1.0" - url-join "^2.0.2" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-download@^3.0.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-3.3.0.tgz#2cfd54d6966c019c4d49ad65fbe65cc9cdef68c8" - dependencies: - debug "^2.2.0" - fs-extra "^0.30.0" - home-path "^1.0.1" - minimist "^1.2.0" - nugget "^2.0.0" - path-exists "^2.1.0" - rc "^1.1.2" - semver "^5.3.0" - sumchecker "^1.2.0" - -electron-stream@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/electron-stream/-/electron-stream-5.1.1.tgz#5805388a6e7ed1be3d982e103726f21863a59ca8" - dependencies: - debug "^2.6.1" - ecstatic "^3.0.0" - electron "^1.7.11" - json-stringify-safe "^5.0.1" - stream-read "^1.1.2" - tempy "0.1.0" - -electron-to-chromium@^1.3.30: - version "1.3.31" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.31.tgz#00d832cba9fe2358652b0c48a8816c8e3a037e9f" - -electron@^1.7.11: - version "1.7.11" - resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.11.tgz#993b6aa79e0e79a7cfcc369f4c813fbd9a0b08d9" - dependencies: - "@types/node" "^7.0.18" - electron-download "^3.0.1" - extract-zip "^1.0.3" - -elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -enstore@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/enstore/-/enstore-1.0.1.tgz#a20fe71eaebde8a3813a0a1240475f55854a81ab" - dependencies: - monotonic-timestamp "0.0.8" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.5.0, es-abstract@^1.7.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.38" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-promise@^4.0.5: - version "4.2.4" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" - -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-standard-jsx@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1" - -eslint-config-standard@10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" - -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" - dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" - -eslint-module-utils@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" - dependencies: - debug "^2.6.8" - pkg-dir "^1.0.0" - -eslint-plugin-import@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" - dependencies: - builtin-modules "^1.1.1" - contains-path "^0.1.0" - debug "^2.2.0" - doctrine "1.5.0" - eslint-import-resolver-node "^0.2.0" - eslint-module-utils "^2.0.0" - has "^1.0.1" - lodash.cond "^4.3.0" - minimatch "^3.0.3" - pkg-up "^1.0.0" - -eslint-plugin-node@~4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz#c04390ab8dbcbb6887174023d6f3a72769e63b97" - dependencies: - ignore "^3.0.11" - minimatch "^3.0.2" - object-assign "^4.0.1" - resolve "^1.1.7" - semver "5.3.0" - -eslint-plugin-promise@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" - -eslint-plugin-react@~6.10.0: - version "6.10.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" - dependencies: - array.prototype.find "^2.0.1" - doctrine "^1.2.2" - has "^1.0.1" - jsx-ast-utils "^1.3.4" - object.assign "^4.0.4" - -eslint-plugin-standard@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" - -eslint@~3.19.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" - dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.5.2" - debug "^2.1.1" - doctrine "^2.0.0" - escope "^3.6.0" - espree "^3.4.0" - esquery "^1.0.0" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.0" - imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" - is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" - levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" - strip-json-comments "~2.0.1" - table "^3.7.8" - text-table "~0.2.0" - user-home "^2.0.0" - -espree@^3.4.0: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" - dependencies: - acorn "^5.2.1" - acorn-jsx "^3.0.0" - -esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - -esquery@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" - dependencies: - estraverse "^4.1.0" - object-assign "^4.0.1" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - -events@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - -extend@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.1.tgz#1ee8010689e7395ff9448241c98652bc759a8260" - -extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extract-zip@^1.0.3: - version "1.6.6" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" - dependencies: - concat-stream "1.6.0" - debug "2.6.9" - mkdirp "0.5.0" - yauzl "2.4.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fast-deep-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -faucet@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/faucet/-/faucet-0.0.1.tgz#597dcf1d2189a2c062321b591e8f151ed2039d9c" - dependencies: - defined "0.0.0" - duplexer "~0.1.1" - minimist "0.0.5" - sprintf "~0.1.3" - tap-parser "~0.4.0" - tape "~2.3.2" - through2 "~0.2.3" - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -find-root@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - -for-each@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" - dependencies: - is-function "~1.0.0" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - -get-stdin@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@~7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^9.14.0, globals@^9.18.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - -has@^1.0.0, has@^1.0.1, has@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -he@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - -headless@~0.1.3: - version "0.1.7" - resolved "https://registry.yarnpkg.com/headless/-/headless-0.1.7.tgz#6e62fae668947f88184d5c156ede7c5695a7e9c8" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -home-path@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.5.tgz#788b29815b12d53bacf575648476e6f9041d133f" - -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" - -html-inject-script@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/html-inject-script/-/html-inject-script-1.1.0.tgz#1a7c10a0fcbd309e85bf53d9a5ed24b74c5e3275" - dependencies: - trumpet "^1.7.1" - -html-select@^2.3.5: - version "2.3.24" - resolved "https://registry.yarnpkg.com/html-select/-/html-select-2.3.24.tgz#46ad6d712e732cf31c6739d5d0110a5fabf17585" - dependencies: - cssauron "^1.1.0" - duplexer2 "~0.0.2" - inherits "^2.0.1" - minimist "~0.0.8" - readable-stream "^1.0.27-1" - split "~0.3.0" - stream-splicer "^1.2.0" - through2 "^1.0.0" - -html-tokenize@^1.1.1: - version "1.2.5" - resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-1.2.5.tgz#7e5ba99ecb51ef906ec9a7fcdee6ca3267c7897e" - dependencies: - inherits "~2.0.1" - minimist "~0.0.8" - readable-stream "~1.0.27-1" - through2 "~0.4.1" - -htmlescape@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" - -http-errors@1.6.2, http-errors@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - -iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - -ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" - -ignore@^3.0.11, ignore@^3.0.9, ignore@^3.2.0: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.3, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -inline-source-map@~0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" - dependencies: - source-map "~0.5.3" - -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - -insert-module-globals@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.7.1" - concat-stream "~1.5.1" - is-buffer "^1.1.0" - lexical-scope "^1.2.0" - process "~0.11.0" - through2 "^2.0.0" - xtend "^4.0.0" - -interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - -invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" - dependencies: - loose-envify "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-buffer@^1.1.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-function@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" - -is-my-json-valid@^2.10.0: - version "2.17.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - dependencies: - path-is-inside "^1.0.1" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -isarray@0.0.1, isarray@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isemail@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -joi@^6.10.1: - version "6.10.1" - resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" - dependencies: - hoek "2.x.x" - isemail "1.x.x" - moment "2.x.x" - topo "1.x.x" - -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -js-yaml@^3.5.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -json-parse-better-errors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stable-stringify@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsonwebtoken@^7.4.1: - version "7.4.3" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz#77f5021de058b605a1783fa1283e99812e645638" - dependencies: - joi "^6.10.1" - jws "^3.1.4" - lodash.once "^4.0.0" - ms "^2.0.0" - xtend "^4.0.1" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -jsx-ast-utils@^1.3.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" - -jwa@^1.1.4: - version "1.1.5" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" - dependencies: - base64url "2.0.0" - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.9" - safe-buffer "^5.0.1" - -jws@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" - dependencies: - base64url "^2.0.0" - jwa "^1.1.4" - safe-buffer "^5.0.1" - -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - optionalDependencies: - graceful-fs "^4.1.9" - -labeled-stream-splicer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" - dependencies: - inherits "^2.0.1" - isarray "~0.0.1" - stream-splicer "^2.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lexical-scope@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" - dependencies: - astw "^2.0.0" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash.cond@^4.3.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" - -lodash.memoize@~3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - -lodash@^4.0.0, lodash@^4.17.4, lodash@^4.3.0: - 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" - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - -md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -meow@^3.1.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - -merge@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.0.0.tgz#b443ab46d837c491e6222056ab0f7933ecb3568f" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.17: - 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@^1.2.11, mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - -minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.5.tgz#d7aa327bcecf518f9106ac6b8f003fa3bcea8566" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1, minimist@~0.0.8: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - dependencies: - minimist "0.0.8" - -mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mkdirp@~0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" - -module-deps@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-5.0.1.tgz#3bc47c14b0a6d925aff2ec4a177b456a96ae0396" - dependencies: - JSONStream "^1.0.3" - browser-resolve "^1.7.0" - cached-path-relative "^1.0.0" - concat-stream "~1.6.0" - defined "^1.0.0" - detective "^5.0.2" - duplexer2 "^0.1.2" - inherits "^2.0.1" - parents "^1.0.0" - readable-stream "^2.0.2" - resolve "^1.1.3" - stream-combiner2 "^1.1.1" - subarg "^1.0.0" - through2 "^2.0.0" - xtend "^4.0.0" - -moment@2.x.x: - version "2.20.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" - -monotonic-timestamp@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/monotonic-timestamp/-/monotonic-timestamp-0.0.8.tgz#67987d02a41c15f568b6c0a05885989dd2402ba0" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -ms@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -nugget@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" - dependencies: - debug "^2.1.3" - minimist "^1.1.0" - pretty-bytes "^1.0.2" - progress-stream "^1.1.0" - request "^2.45.0" - single-line-log "^1.1.2" - throttleit "0.0.2" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object-inspect@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.3.0.tgz#5b1eb8e6742e2ee83342a637034d844928ba2f6d" - -object-keys@^1.0.11, object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" - -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - -object.assign@^4.0.4: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -optimist@^0.6.1, optimist@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -ordered-emitter@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ordered-emitter/-/ordered-emitter-0.1.1.tgz#aa20bdafbdcc1631834a350f68b4ef8eb34eed7b" - -os-browserify@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - dependencies: - p-limit "^1.1.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - -pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - -parents@^1.0.0, parents@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" - dependencies: - path-platform "~0.11.15" - -parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -path-browserify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - -path-exists@^2.0.0, path-exists@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-platform@~0.11.15: - version "0.11.15" - resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -phantomjs-stream@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/phantomjs-stream/-/phantomjs-stream-1.1.1.tgz#5650f42028c09e846bc463b82bf4cafc43a3ba2b" - dependencies: - stream-read "^1.1.2" - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-conf@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" - dependencies: - find-up "^2.0.0" - load-json-file "^4.0.0" - -pkg-config@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" - dependencies: - debug-log "^1.0.0" - find-root "^1.0.0" - xtend "^4.0.1" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" - -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - -plist@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/plist/-/plist-0.2.1.tgz#f3a3de07885d773e66d8a96782f1bec28cf2b2d0" - dependencies: - sax "0.1.x" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -pretty-bytes@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" - dependencies: - get-stdin "^4.0.1" - meow "^3.1.0" - -private@^0.1.6, private@^0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -process@~0.11.0: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - -progress-stream@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" - dependencies: - speedometer "~0.1.2" - through2 "~0.2.3" - -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - -public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - -punycode@^1.3.2, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -pusher-chatkit-server@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/pusher-chatkit-server/-/pusher-chatkit-server-0.9.1.tgz#b80710e779383485df48fa3a64dba6bd5d8799d1" - dependencies: - jsonwebtoken "^7.4.1" - pusher-platform-node "~0.11.1" - -pusher-platform-node@~0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/pusher-platform-node/-/pusher-platform-node-0.11.1.tgz#29ccc2de4cc2009a789517e09dc6bf3639013b0d" - dependencies: - body-parser "^1.17.2" - extend "^2.0.1" - jsonwebtoken "^7.4.1" - request "^2.81.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" - -querystring-es3@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - -ramda@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62" - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" - unpipe "1.0.0" - -rc@^1.1.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.4.tgz#a0f606caae2a3b862bbd0ef85482c0125b315fa3" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -read-only-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" - dependencies: - readable-stream "^2.0.2" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0.27-1, readable-stream@^1.1.13-1, readable-stream@~1.1.11, readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@~1.0.17, readable-stream@~1.0.27-1: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readable-wrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/readable-wrap/-/readable-wrap-1.0.0.tgz#3b5a211c631e12303a54991c806c17e7ae206bff" - dependencies: - readable-stream "^1.1.13-1" - -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -request@^2.45.0, request@^2.81.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -require-uncached@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - -resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7: - version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" - dependencies: - path-parse "^1.0.5" - -resolve@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" - dependencies: - path-parse "^1.0.5" - -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" - -resumer@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" - dependencies: - through "~2.3.4" - -rimraf@^2.2.8: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" - dependencies: - hash-base "^2.0.0" - inherits "^2.0.1" - -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - dependencies: - once "^1.3.0" - -run-parallel@^1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" - -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -sax@0.1.x: - version "0.1.5" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.1.5.tgz#d1829a6120fa01665eb4dbff6c43f29fd6d61471" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -semver@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -server-destroy@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" - -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - -sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: - version "2.4.10" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shasum@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" - dependencies: - json-stable-stringify "~0.0.0" - sha.js "~2.4.4" - -shell-quote@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - dependencies: - array-filter "~0.0.0" - array-map "~0.0.0" - array-reduce "~0.0.0" - jsonify "~0.0.0" - -shelljs@^0.7.5: - version "0.7.8" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -single-line-log@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" - dependencies: - string-width "^1.0.1" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - -snazzy@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/snazzy/-/snazzy-7.0.0.tgz#95edaccc4a8d6f80f4ac5cc7b520e8f8f9ac2325" - dependencies: - chalk "^1.1.0" - inherits "^2.0.1" - minimist "^1.1.1" - readable-stream "^2.0.6" - standard-json "^1.0.0" - text-table "^0.2.0" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - -source-map-support@^0.4.0, source-map-support@^0.4.15: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - dependencies: - source-map "^0.5.6" - -source-map@^0.5.6, source-map@~0.5.3: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" - dependencies: - spdx-license-ids "^1.0.2" - -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" - -speedometer@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" - -split@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/split/-/split-0.1.2.tgz#f0710744c453d551fc7143ead983da6014e336cc" - dependencies: - through "1" - -split@~0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - dependencies: - through "2" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -sprintf@~0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/sprintf/-/sprintf-0.1.5.tgz#8f83e39a9317c1a502cb7db8050e51c679f6edcf" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -standard-engine@~7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-7.0.0.tgz#ebb77b9c8fc2c8165ffa353bd91ba0dff41af690" - dependencies: - deglob "^2.1.0" - get-stdin "^5.0.1" - minimist "^1.1.0" - pkg-conf "^2.0.0" - -standard-json@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/standard-json/-/standard-json-1.0.2.tgz#82dea4a14c78cd9e35d38cde4b88ac6b62596a23" - dependencies: - concat-stream "^1.5.0" - -standard@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/standard/-/standard-10.0.3.tgz#7869bcbf422bdeeaab689a1ffb1fea9677dd50ea" - dependencies: - eslint "~3.19.0" - eslint-config-standard "10.2.1" - eslint-config-standard-jsx "4.0.2" - eslint-plugin-import "~2.2.0" - eslint-plugin-node "~4.2.2" - eslint-plugin-promise "~3.5.0" - eslint-plugin-react "~6.10.0" - eslint-plugin-standard "~3.0.1" - standard-engine "~7.0.0" - -"statuses@>= 1.3.1 < 2": - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - -stream-browserify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-combiner2@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - dependencies: - duplexer2 "~0.1.0" - readable-stream "^2.0.2" - -stream-http@^2.0.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.3" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-read@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/stream-read/-/stream-read-1.1.2.tgz#3137110d7aa80ba54e4b829c4cd33ca106b9564d" - dependencies: - dezalgo "^1.0.1" - -stream-splicer@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-1.3.2.tgz#3c0441be15b9bf4e226275e6dc83964745546661" - dependencies: - indexof "0.0.1" - inherits "^2.0.1" - isarray "~0.0.1" - readable-stream "^1.1.13-1" - readable-wrap "^1.0.0" - through2 "^1.0.0" - -stream-splicer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.2" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string.prototype.trim@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.0" - function-bind "^1.0.2" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.0, string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -subarg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" - dependencies: - minimist "^1.1.0" - -sumchecker@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-1.3.1.tgz#79bb3b4456dd04f18ebdbc0d703a1d1daec5105d" - dependencies: - debug "^2.2.0" - es6-promise "^4.0.5" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -syntax-error@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.3.0.tgz#1ed9266c4d40be75dc55bf9bb1cb77062bb96ca1" - dependencies: - acorn "^4.0.3" - -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" - dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" - -tap-parser@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-0.2.1.tgz#8e1e823f2114ee21d032e2f31e4fb642a296f50b" - dependencies: - split "~0.1.2" - -tap-parser@~0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-0.4.3.tgz#a4eae190c10d76c7a111921ff38bbe4d58f09eea" - dependencies: - inherits "~2.0.1" - readable-stream "~1.1.11" - -tape-run@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/tape-run/-/tape-run-3.0.2.tgz#fbad4b77b72bab77c36e5f1c3610bfa17402c46d" - dependencies: - "@juliangruber/tap-finished" "0.0.2" - browser-run "^4.1.1" - optimist "~0.6.1" - through "~2.3.4" - throughout "0.0.0" - -tape@^4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.8.0.tgz#f6a9fec41cc50a1de50fa33603ab580991f6068e" - dependencies: - deep-equal "~1.0.1" - defined "~1.0.0" - for-each "~0.3.2" - function-bind "~1.1.0" - glob "~7.1.2" - has "~1.0.1" - inherits "~2.0.3" - minimist "~1.2.0" - object-inspect "~1.3.0" - resolve "~1.4.0" - resumer "~0.0.0" - string.prototype.trim "~1.1.2" - through "~2.3.8" - -tape@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tape/-/tape-2.3.3.tgz#2e7ce0a31df09f8d6851664a71842e0ca5057af7" - dependencies: - deep-equal "~0.1.0" - defined "~0.0.0" - inherits "~2.0.1" - jsonify "~0.0.0" - resumer "~0.0.0" - through "~2.3.4" - -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - -tempy@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.1.0.tgz#8527413cd07100834fcc9cbb8242be95ba0e1fee" - dependencies: - pify "^2.3.0" - temp-dir "^1.0.0" - unique-string "^1.0.0" - -text-table@^0.2.0, text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -throttleit@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - -through2@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" - dependencies: - readable-stream ">=1.1.13-1 <1.2.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through2@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" - dependencies: - readable-stream "~1.1.9" - xtend "~2.1.1" - -through2@~0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" - dependencies: - readable-stream "~1.0.17" - xtend "~2.1.1" - -through@1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/through/-/through-1.1.2.tgz#344a5425a3773314ca7e0eb6512fbafaf76c0bfe" - -through@2, "through@>=2.2.7 <3", through@X.X.X, through@^2.3.6, through@^2.3.8, through@~2.3.4, through@~2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -throughout@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/throughout/-/throughout-0.0.0.tgz#da935527231a7944daa60d3ad47a32429af1a8c1" - dependencies: - duplexer "~0.0.2" - through "~2.3.4" - -timers-browserify@^1.0.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" - dependencies: - process "~0.11.0" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - -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" - -topo@1.x.x: - version "1.1.0" - resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" - dependencies: - hoek "2.x.x" - -tough-cookie@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -trumpet@^1.7.1: - version "1.7.2" - resolved "https://registry.yarnpkg.com/trumpet/-/trumpet-1.7.2.tgz#b02c69e465d171f55e44924bf9b5bdd20974c830" - dependencies: - duplexer2 "~0.0.2" - html-select "^2.3.5" - html-tokenize "^1.1.1" - inherits "^2.0.0" - readable-stream "^1.0.27-1" - through2 "^1.0.0" - -tty-browserify@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -type-is@~1.6.15: - version "1.6.15" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.15" - -typedarray@^0.0.6, typedarray@~0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -umd@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - dependencies: - crypto-random-string "^1.0.0" - -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - -url-join@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - -url@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -util@0.10.3, util@~0.10.1: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - dependencies: - inherits "2.0.1" - -uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - -validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" - dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vm-browserify@~0.0.1: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - dependencies: - indexof "0.0.1" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - -xhr-write-stream@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/xhr-write-stream/-/xhr-write-stream-0.1.2.tgz#e357848e0d039b411fdd5b3bf81be47ee5ce26aa" - dependencies: - concat-stream "~0.1.0" - ordered-emitter "~0.1.0" - -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - dependencies: - object-keys "~0.4.0" - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 6da9415..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "declarationDir": "declarations", - "lib": ["ES6", "webworker"], - "module": "commonjs", - "removeComments": true, - "sourceMap": true, - "strict": true, - "target": "ES5" - }, - "exclude": [ - "node_modules", - "target", - "test" - ] -} diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 5146547..0000000 --- a/tslint.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended", - "tslint-config-prettier" - ], - "jsRules": {}, - "linterOptions": {}, - "rules": { - "arrow-parens": false, - "interface-name": [true, "never-prefix"], - "interface-over-type-literal": false, - "max-classes-per-file": [false], - "member-access": [true, "no-public"], - "member-ordering": [true, {"order": "instance-sandwich"}], - "quotemark": [ - true, - "single", - "avoid-escape" - ], - "semicolon": [true, "always", "ignore-bound-class-methods"] - }, - "rulesDirectory": [] -} diff --git a/webpack/config.react-native.js b/webpack/config.react-native.js deleted file mode 100644 index 31ea86b..0000000 --- a/webpack/config.react-native.js +++ /dev/null @@ -1,21 +0,0 @@ -var _ = require('lodash'); -var path = require('path'); - -var sharedConfig = require('./config.shared'); - -module.exports = _.merge(sharedConfig, { - entry: { - 'chatkit': './src/index.ts' - }, - output: { - library: "Chatkit", - libraryTarget:"commonjs2", - path: path.join(__dirname, "../dist/react-native"), - filename: "chatkit.js" - }, - resolve: { - alias: { - ['pusher-platform$']: path.resolve(__dirname, '../node_modules/pusher-platform/react-native') - } - } -}) diff --git a/webpack/config.shared.js b/webpack/config.shared.js deleted file mode 100644 index bee80ca..0000000 --- a/webpack/config.shared.js +++ /dev/null @@ -1,16 +0,0 @@ -var webpack = require('webpack'); - -module.exports = { - resolve: { - extensions: ['.ts', '.js'], - }, - module: { - rules: [ - { - test: /\.ts$/, - loader: `ts-loader?${ JSON.stringify({ logInfoToStdOut: true }) }`, - exclude: [/node_modules/, /dist/, /example/] - } - ], - }, -}; diff --git a/webpack/config.web.js b/webpack/config.web.js deleted file mode 100644 index 57ab6a1..0000000 --- a/webpack/config.web.js +++ /dev/null @@ -1,17 +0,0 @@ -var _ = require('lodash'); -var path = require('path'); -var webpack = require('webpack'); - -var sharedConfig = require('./config.shared'); - -module.exports = _.merge(sharedConfig, { - entry: { - 'chatkit': './src/index.ts' - }, - output: { - library: "Chatkit", - path: path.join(__dirname, "../dist/web"), - filename: "chatkit.js", - libraryTarget: "umd" - } -}); diff --git a/webpack/config.worker.js b/webpack/config.worker.js deleted file mode 100644 index 8b615ae..0000000 --- a/webpack/config.worker.js +++ /dev/null @@ -1,21 +0,0 @@ -var _ = require('lodash'); -var path = require('path'); -var webpack = require('webpack'); - -var sharedConfig = require('./config.shared'); - -module.exports = _.merge(sharedConfig, { - entry: { - 'chatkit.worker': './src/index.ts' - }, - output: { - library: "Chatkit", - path: path.join(__dirname, "../dist/worker"), - filename: "chatkit.worker.js" - }, - resolve: { - alias: { - ['pusher-platform$']: path.resolve(__dirname, '../node_modules/pusher-platform/worker') - } - } -}); diff --git a/yarn.lock b/yarn.lock index 0c36440..c84130b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,51 +2,72 @@ # yarn lockfile v1 -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" +"@browserify/acorn5-object-spread@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@browserify/acorn5-object-spread/-/acorn5-object-spread-5.0.1.tgz#92e9b37f97beac9ec429a3cc479ded380297540c" + dependencies: + acorn "^5.2.1" -acorn-dynamic-import@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" +"@juliangruber/tap-finished@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@juliangruber/tap-finished/-/tap-finished-0.0.2.tgz#a9aad63d5e4425ff8a6d9a6a94ab287a1b595dbe" dependencies: - acorn "^4.0.3" + once "^1.3.3" + tap-parser "~0.2.0" + through "~2.3.4" + +"@types/node@^7.0.18": + version "7.0.52" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716" + +JSONStream@^1.0.3: + version "1.3.2" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" +acorn@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" -ajv-keywords@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.9.1: +ajv@^4.7.0: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.1.5: - version "5.5.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.1.tgz#b38bb8876d9e86bee994956a04e721e88b248eb2" +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" ansi-regex@^2.0.0: version "2.1.1" @@ -60,43 +81,52 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: - color-convert "^1.9.0" + sprintf-js "~1.0.2" -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" + array-uniq "^1.0.1" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array.prototype.find@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" dependencies: - arr-flatten "^1.0.1" + define-properties "^1.1.2" + es-abstract "^1.7.0" -arr-flatten@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" asn1.js@^4.0.0: version "4.9.2" @@ -114,39 +144,31 @@ assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -assert@^1.1.1: +assert@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" dependencies: util "0.10.3" -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - -async@^2.1.2: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" +astw@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/astw/-/astw-2.2.0.tgz#7bd41784d32493987aeb239b6b4e1c57a873b917" dependencies: - lodash "^4.14.0" + acorn "^4.0.3" asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" -aws4@^1.2.1: +aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.16.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -154,7 +176,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.25.0, babel-core@^6.26.0: +babel-core@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: @@ -292,14 +314,6 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-loader@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126" - dependencies: - find-cache-dir "^1.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" - babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" @@ -320,6 +334,10 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" @@ -508,6 +526,13 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" @@ -521,7 +546,7 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-preset-env@^1.6.0: +babel-preset-env@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" dependencies: @@ -608,6 +633,10 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" +babelify@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-8.0.0.tgz#6f60f5f062bfe7695754ef2403b842014a580ed3" + babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -620,35 +649,46 @@ base64-js@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" +body-parser@^1.17.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" dependencies: - hoek "2.x.x" + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" brace-expansion@^1.1.7: version "1.1.8" @@ -657,18 +697,56 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" +browser-launcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-launcher/-/browser-launcher-1.0.0.tgz#0cf0ff1ecdcb7516c8f973bf82eb6f3bf929ce97" + dependencies: + headless "~0.1.3" + merge "~1.0.0" + minimist "0.0.5" + mkdirp "~0.3.3" + plist "0.2.1" + xtend "^4.0.0" + +browser-pack@^6.0.1: + version "6.0.3" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.3.tgz#91ca96518583ef580ab063a309de62e407767a39" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + +browser-run@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/browser-run/-/browser-run-4.1.1.tgz#f90b35a12c9d2a8b0bd5ce139680409e8c00ba4a" + dependencies: + browser-launcher "^1.0.0" + duplexer "^0.1.1" + ecstatic "^2.0.0" + electron-stream "^5.1.1" + enstore "^1.0.1" + html-inject-script "^1.1.0" + optimist "^0.6.1" + phantomjs-stream "^1.1.1" + server-destroy "^1.0.1" + source-map-support "^0.4.0" + through "^2.3.8" + xhr-write-stream "^0.1.2" + xtend "^4.0.1" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" @@ -715,30 +793,86 @@ browserify-sign@^4.0.0: inherits "^2.0.1" parse-asn1 "^5.0.0" -browserify-zlib@^0.2.0: +browserify-zlib@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" dependencies: pako "~1.0.5" +browserify@^15.2.0: + version "15.2.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-15.2.0.tgz#1e121ba1fa72cf9fd2d8df002f8674b68b45df89" + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.2.0" + buffer "^5.0.2" + cached-path-relative "^1.0.0" + concat-stream "~1.5.1" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "~1.1.0" + duplexer2 "~0.1.2" + events "~1.1.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + mkdirp "^0.5.0" + module-deps "^5.0.1" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "~1.0.0" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "~0.0.0" + url "~0.11.0" + util "~0.10.1" + vm-browserify "~0.0.1" + xtend "^4.0.0" + browserslist@^2.1.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz#bac5ee1cc69ca9d96403ffb8a3abdc5b6aed6346" + version "2.11.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" dependencies: - caniuse-lite "^1.0.30000780" - electron-to-chromium "^1.3.28" + caniuse-lite "^1.0.30000792" + electron-to-chromium "^1.3.30" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" -buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" +buffer@^5.0.2: + version "5.0.8" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" - isarray "^1.0.0" builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" @@ -748,30 +882,44 @@ builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" +cached-path-relative@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" -caniuse-lite@^1.0.30000780: - version "1.0.30000782" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000782.tgz#5b82b8c385f25348745c471ca51320afb1b7f254" +caniuse-lite@^1.0.30000792: + version "1.0.30000792" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000792.tgz#d0cea981f8118f3961471afbb43c9a1e5bbf0332" caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.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" dependencies: @@ -781,29 +929,6 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1, chalk@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" - dependencies: - ansi-styles "^3.1.0" - escape-string-regexp "^1.0.5" - supports-color "^4.0.0" - -chokidar@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -811,21 +936,19 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" co@^4.6.0: version "4.6.0" @@ -835,15 +958,23 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" +combine-source-map@~0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" dependencies: - color-name "^1.1.1" + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" -color-name@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" +combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" @@ -851,39 +982,59 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@^2.9.0: - version "2.12.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - 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.6.0, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-0.1.1.tgz#d7f4e278b90cfc4f0f3ef77fe4c03b40eb3f7900" + +concat-stream@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" dependencies: date-now "^0.1.4" -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -constants-browserify@^1.0.0: +constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +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.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + core-js@^2.4.0, core-js@^2.5.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.2.tgz#bc4648656e7dc9dc80d7d3c7bbc172d96e744e63" + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -916,21 +1067,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" dependencies: - boom "2.x.x" + boom "5.x.x" -crypto-browserify@^3.11.0: +crypto-browserify@^3.0.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" dependencies: @@ -946,6 +1089,22 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + +cssauron@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" + dependencies: + through X.X.X + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -962,27 +1121,94 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@^2.2.0, debug@^2.6.8: +debug-log@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" + +debug@2.6.9, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.1, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1: +decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" +deep-equal@~0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +defined@0.0.0, defined@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" + +defined@^1.0.0, defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +deglob@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.0.tgz#4d44abe16ef32c779b4972bd141a80325029a14a" + dependencies: + find-root "^1.0.0" + glob "^7.0.5" + ignore "^3.0.9" + pkg-config "^1.1.0" + run-parallel "^1.1.2" + uniq "^1.0.1" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +deps-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" + dependencies: + JSONStream "^1.0.3" + shasum "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" des.js@^1.0.0: version "1.0.0" @@ -997,13 +1223,20 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" +detective@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.0.2.tgz#84ec2e1c581e74211e2ae4ffce1edf52c3263f84" + dependencies: + "@browserify/acorn5-object-spread" "^5.0.1" + acorn "^5.2.1" + defined "^1.0.0" -diff@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" +dezalgo@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + dependencies: + asap "^2.0.0" + wrappy "1" diffie-hellman@^5.0.0: version "5.0.2" @@ -1013,19 +1246,114 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -domain-browser@^1.1.1: +doctrine@1.5.0, doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +domain-browser@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer2@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexer@~0.0.2: + version "0.0.4" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.0.4.tgz#afcb7f1f8b8d74f820726171d5d64ac9e4a8ff20" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" -electron-to-chromium@^1.3.28: - version "1.3.28" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz#8dd4e6458086644e9f9f0a1cf32e2a1f9dffd9ee" +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" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + +ecstatic@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-2.2.1.tgz#b5087fad439dd9dd49d31e18131454817fe87769" + dependencies: + he "^1.1.1" + mime "^1.2.11" + minimist "^1.1.0" + url-join "^2.0.2" + +ecstatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.1.1.tgz#2564aa9dde84179dcaf926a9e6d12df13a0b666d" + dependencies: + he "^1.1.1" + mime "^1.4.1" + minimist "^1.1.0" + url-join "^2.0.2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +electron-download@^3.0.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-3.3.0.tgz#2cfd54d6966c019c4d49ad65fbe65cc9cdef68c8" + dependencies: + debug "^2.2.0" + fs-extra "^0.30.0" + home-path "^1.0.1" + minimist "^1.2.0" + nugget "^2.0.0" + path-exists "^2.1.0" + rc "^1.1.2" + semver "^5.3.0" + sumchecker "^1.2.0" + +electron-stream@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/electron-stream/-/electron-stream-5.1.1.tgz#5805388a6e7ed1be3d982e103726f21863a59ca8" + dependencies: + debug "^2.6.1" + ecstatic "^3.0.0" + electron "^1.7.11" + json-stringify-safe "^5.0.1" + stream-read "^1.1.2" + tempy "0.1.0" + +electron-to-chromium@^1.3.30: + version "1.3.31" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.31.tgz#00d832cba9fe2358652b0c48a8816c8e3a037e9f" + +electron@^1.7.11: + version "1.7.11" + resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.11.tgz#993b6aa79e0e79a7cfcc369f4c813fbd9a0b08d9" + dependencies: + "@types/node" "^7.0.18" + electron-download "^3.0.1" + extract-zip "^1.0.3" elliptic@^6.0.0: version "6.4.0" @@ -1039,39 +1367,44 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - -enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - object-assign "^4.0.1" - tapable "^0.2.7" - -errno@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.5.tgz#a563781a6052bc2c9ccd89e8cef0eb9506e0c321" +enstore@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/enstore/-/enstore-1.0.1.tgz#a20fe71eaebde8a3813a0a1240475f55854a81ab" dependencies: - prr "~1.0.1" + monotonic-timestamp "0.0.8" -error-ex@^1.2.0: +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" +es-abstract@^1.5.0, es-abstract@^1.7.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.37" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" + version "0.10.38" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3" dependencies: - es6-iterator "~2.0.1" + es6-iterator "~2.0.3" es6-symbol "~3.1.1" -es6-iterator@^2.0.1, es6-iterator@~2.0.1: +es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: @@ -1090,6 +1423,10 @@ es6-map@^0.1.3: es6-symbol "~3.1.1" event-emitter "~0.3.5" +es6-promise@^4.0.5: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -1129,14 +1466,137 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -esrecurse@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" +eslint-config-standard-jsx@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1" + +eslint-config-standard@10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" + +eslint-import-resolver-node@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" + dependencies: + debug "^2.2.0" + object-assign "^4.0.1" + resolve "^1.1.6" + +eslint-module-utils@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.2.0" + doctrine "1.5.0" + eslint-import-resolver-node "^0.2.0" + eslint-module-utils "^2.0.0" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + pkg-up "^1.0.0" + +eslint-plugin-node@~4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz#c04390ab8dbcbb6887174023d6f3a72769e63b97" + dependencies: + ignore "^3.0.11" + minimatch "^3.0.2" + object-assign "^4.0.1" + resolve "^1.1.7" + semver "5.3.0" + +eslint-plugin-promise@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" + +eslint-plugin-react@~6.10.0: + version "6.10.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" + dependencies: + array.prototype.find "^2.0.1" + doctrine "^1.2.2" + has "^1.0.1" + jsx-ast-utils "^1.3.4" + object.assign "^4.0.4" + +eslint-plugin-standard@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" + +eslint@~3.19.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.5.2" + debug "^2.1.1" + doctrine "^2.0.0" + escope "^3.6.0" + espree "^3.4.0" + esquery "^1.0.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.14.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~2.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.4.0: + version "3.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" + dependencies: + acorn "^5.2.1" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -1151,7 +1611,7 @@ event-emitter@~0.3.5: d "1" es5-ext "~0.10.14" -events@^1.0.0: +events@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -1162,39 +1622,26 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" +extend@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.1.tgz#1ee8010689e7395ff9448241c98652bc759a8260" -extend@~3.0.0: +extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" +extract-zip@^1.0.3: + version "1.6.6" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" dependencies: - is-extglob "^1.0.0" + concat-stream "1.6.0" + debug "2.6.9" + mkdirp "0.5.0" + yauzl "2.4.1" extsprintf@1.3.0: version "1.3.0" @@ -1212,104 +1659,125 @@ fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +faucet@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/faucet/-/faucet-0.0.1.tgz#597dcf1d2189a2c062321b591e8f151ed2039d9c" + dependencies: + defined "0.0.0" + duplexer "~0.1.1" + minimist "0.0.5" + sprintf "~0.1.3" + tap-parser "~0.4.0" + tape "~2.3.2" + through2 "~0.2.3" -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" + pend "~1.2.0" -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +find-root@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" + path-exists "^2.0.0" + pinkie-promise "^2.0.0" -find-up@^2.0.0, find-up@^2.1.0: +find-up@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" +for-each@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" dependencies: - for-in "^1.0.1" + is-function "~1.0.0" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" mime-types "^2.1.12" +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" +function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" + is-property "^1.0.0" -get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" getpass@^0.1.1: version "0.1.7" @@ -1317,20 +1785,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob@^7.0.5, glob@^7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@~7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -1341,24 +1796,35 @@ glob@^7.0.5, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^9.18.0: +globals@^9.14.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" -graceful-fs@^4.1.2: +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" + ajv "^5.1.0" + har-schema "^2.0.0" has-ansi@^2.0.0: version "2.0.0" @@ -1366,13 +1832,15 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +has@^1.0.0, has@^1.0.1, has@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" hash-base@^2.0.0: version "2.0.2" @@ -1394,14 +1862,22 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.0" -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +he@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +headless@~0.1.3: + version "0.1.7" + resolved "https://registry.yarnpkg.com/headless/-/headless-0.1.7.tgz#6e62fae668947f88184d5c156ede7c5695a7e9c8" hmac-drbg@^1.0.0: version "1.0.1" @@ -1415,6 +1891,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -1422,15 +1902,60 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +home-path@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.5.tgz#788b29815b12d53bacf575648476e6f9041d133f" + 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" -http-signature@~1.1.0: +html-inject-script@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/html-inject-script/-/html-inject-script-1.1.0.tgz#1a7c10a0fcbd309e85bf53d9a5ed24b74c5e3275" + dependencies: + trumpet "^1.7.1" + +html-select@^2.3.5: + version "2.3.24" + resolved "https://registry.yarnpkg.com/html-select/-/html-select-2.3.24.tgz#46ad6d712e732cf31c6739d5d0110a5fabf17585" + dependencies: + cssauron "^1.1.0" + duplexer2 "~0.0.2" + inherits "^2.0.1" + minimist "~0.0.8" + readable-stream "^1.0.27-1" + split "~0.3.0" + stream-splicer "^1.2.0" + through2 "^1.0.0" + +html-tokenize@^1.1.1: + version "1.2.5" + resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-1.2.5.tgz#7e5ba99ecb51ef906ec9a7fcdee6ca3267c7897e" + dependencies: + inherits "~2.0.1" + minimist "~0.0.8" + readable-stream "~1.0.27-1" + through2 "~0.4.1" + +htmlescape@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + +http-errors@1.6.2, http-errors@~1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" dependencies: - assert-plus "^0.2.0" + assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" @@ -1438,10 +1963,28 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +ignore@^3.0.11, ignore@^3.0.9, ignore@^3.2.0: + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" @@ -1453,7 +1996,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -1465,6 +2008,43 @@ ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + dependencies: + source-map "~0.5.3" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +insert-module-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.7.1" + concat-stream "~1.5.1" + is-buffer "^1.1.0" + lexical-scope "^1.2.0" + process "~0.11.0" + through2 "^2.0.0" + xtend "^4.0.0" + interpret@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" @@ -1475,21 +2055,11 @@ invariant@^2.2.2: 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" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: +is-buffer@^1.1.0: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -1499,23 +2069,13 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" is-finite@^1.0.0: version "1.0.2" @@ -1533,62 +2093,97 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" +is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + +is-my-json-valid@^2.10.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" dependencies: - is-extglob "^1.0.0" + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" dependencies: - kind-of "^3.0.2" + is-path-inside "^1.0.0" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: - kind-of "^3.0.2" + path-is-inside "^1.0.1" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" -is-stream@^1.1.0: +is-resolvable@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +isarray@0.0.1, isarray@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" +isemail@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +joi@^6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" + dependencies: + hoek "2.x.x" + isemail "1.x.x" + moment "2.x.x" + topo "1.x.x" + js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +js-yaml@^3.5.1: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -1601,9 +2196,9 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" -json-loader@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" +json-parse-better-errors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" json-schema-traverse@^0.3.0: version "0.3.1" @@ -1613,24 +2208,54 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.1: +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.1: +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json5@^0.5.0, json5@^0.5.1: +json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsonwebtoken@^7.4.1: + version "7.4.3" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz#77f5021de058b605a1783fa1283e99812e645638" + dependencies: + joi "^6.10.1" + jws "^3.1.4" + lodash.once "^4.0.0" + ms "^2.0.0" + xtend "^4.0.1" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -1640,48 +2265,72 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" +jsx-ast-utils@^1.3.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" + +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" dependencies: - is-buffer "^1.1.5" + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" +jws@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" dependencies: - is-buffer "^1.1.5" + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" +labeled-stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" + dependencies: + inherits "^2.0.1" + isarray "~0.0.1" + stream-splicer "^2.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: - invert-kv "^1.0.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" +lexical-scope@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" + dependencies: + astw "^2.0.0" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" pify "^2.0.0" - strip-bom "^3.0.0" - -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" -loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" locate-path@^2.0.0: version "2.0.0" @@ -1690,32 +2339,38 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash@^4.14.0, lodash@^4.17.4: +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash@^4.0.0, lodash@^4.17.4, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - 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" -lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" -make-dir@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.1.0.tgz#19b4369fe48c116f53c2af95ad102c0e39e85d51" - dependencies: - pify "^3.0.0" +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" md5.js@^1.3.4: version "1.3.4" @@ -1724,36 +2379,28 @@ md5.js@^1.3.4: hash-base "^3.0.0" inherits "^2.0.1" -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - dependencies: - mimic-fn "^1.0.0" +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +meow@^3.1.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" -memory-fs@^0.4.0, memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" +merge@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.0.0.tgz#b443ab46d837c491e6222056ab0f7933ecb3568f" miller-rabin@^4.0.0: version "4.0.1" @@ -1766,15 +2413,15 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" -mime-types@^2.1.12, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.17: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" -mimic-fn@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" +mime@^1.2.11, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" minimalistic-assert@^1.0.0: version "1.0.0" @@ -1784,86 +2431,89 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" +minimist@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.5.tgz#d7aa327bcecf518f9106ac6b8f003fa3bcea8566" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.2.0: +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" -"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0: +minimist@~0.0.1, minimist@~0.0.8: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + +mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +mkdirp@~0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + +module-deps@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-5.0.1.tgz#3bc47c14b0a6d925aff2ec4a177b456a96ae0396" + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.0" + concat-stream "~1.6.0" + defined "^1.0.0" + detective "^5.0.2" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.1.3" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +moment@2.x.x: + version "2.20.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" + +monotonic-timestamp@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/monotonic-timestamp/-/monotonic-timestamp-0.0.8.tgz#67987d02a41c15f568b6c0a05885989dd2402ba0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -nan@^2.3.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" +ms@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.0" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -normalize-package-data@^2.3.2: +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -1872,32 +2522,23 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" +nugget@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" + debug "^2.1.3" + minimist "^1.1.0" + pretty-bytes "^1.0.2" + progress-stream "^1.1.0" + request "^2.45.0" + single-line-log "^1.1.2" + throttleit "0.0.2" number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1: +oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -1905,12 +2546,32 @@ object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" +object-inspect@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.3.0.tgz#5b1eb8e6742e2ee83342a637034d844928ba2f6d" + +object-keys@^1.0.11, object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object.assign@^4.0.4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" + ee-first "1.1.1" once@^1.3.0, once@^1.3.3: version "1.4.0" @@ -1918,7 +2579,33 @@ once@^1.3.0, once@^1.3.3: dependencies: wrappy "1" -os-browserify@^0.3.0: +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +optimist@^0.6.1, optimist@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ordered-emitter@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ordered-emitter/-/ordered-emitter-0.1.1.tgz#aa20bdafbdcc1631834a350f68b4ef8eb34eed7b" + +os-browserify@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" @@ -1926,32 +2613,15 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - p-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" @@ -1959,10 +2629,20 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + dependencies: + path-platform "~0.11.15" + parse-asn1@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" @@ -1973,25 +2653,29 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" -path-browserify@0.0.0: +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +path-browserify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" +path-exists@^2.0.0, path-exists@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -2000,19 +2684,25 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: + graceful-fs "^4.1.2" pify "^2.0.0" + pinkie-promise "^2.0.0" pbkdf2@^3.0.3: version "3.0.14" @@ -2024,11 +2714,21 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +phantomjs-stream@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/phantomjs-stream/-/phantomjs-stream-1.1.1.tgz#5650f42028c09e846bc463b82bf4cafc43a3ba2b" + dependencies: + stream-read "^1.1.2" -pify@^2.0.0: +pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2036,19 +2736,63 @@ pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: - find-up "^2.1.0" + pinkie "^2.0.0" -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-conf@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" + dependencies: + find-up "^2.0.0" + load-json-file "^4.0.0" -prettier@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.1.tgz#41638a0d47c1efbd1b7d5a742aaa5548eab86d70" +pkg-config@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" + dependencies: + debug-log "^1.0.0" + find-root "^1.0.0" + xtend "^4.0.1" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pkg-up@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" + dependencies: + find-up "^1.0.0" + +plist@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/plist/-/plist-0.2.1.tgz#f3a3de07885d773e66d8a96782f1bec28cf2b2d0" + dependencies: + sax "0.1.x" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +pretty-bytes@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" + dependencies: + get-stdin "^4.0.1" + meow "^3.1.0" private@^0.1.6, private@^0.1.7: version "0.1.8" @@ -2058,17 +2802,20 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -process@^0.11.10: +process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" +progress-stream@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" + dependencies: + speedometer "~0.1.2" + through2 "~0.2.3" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" public-encrypt@^4.0.0: version "4.0.0" @@ -2084,19 +2831,35 @@ punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" -punycode@^1.2.4, punycode@^1.4.1: +punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +pusher-chatkit-server@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/pusher-chatkit-server/-/pusher-chatkit-server-0.9.1.tgz#b80710e779383485df48fa3a64dba6bd5d8799d1" + dependencies: + jsonwebtoken "^7.4.1" + pusher-platform-node "~0.11.1" + +pusher-platform-node@~0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/pusher-platform-node/-/pusher-platform-node-0.11.1.tgz#29ccc2de4cc2009a789517e09dc6bf3639013b0d" + dependencies: + body-parser "^1.17.2" + extend "^2.0.1" + jsonwebtoken "^7.4.1" + request "^2.81.0" + pusher-platform@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/pusher-platform/-/pusher-platform-0.14.0.tgz#81b410b51c4b1cc31e24d79295af8ef947c3c307" -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +qs@6.5.1, qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" -querystring-es3@^0.2.0: +querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -2104,16 +2867,13 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" dependencies: safe-buffer "^5.1.0" @@ -2124,31 +2884,55 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -rc@^1.1.7: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +rc@^1.1.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.4.tgz#a0f606caae2a3b862bbd0ef85482c0125b315fa3" dependencies: deep-extend "~0.4.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" -read-pkg-up@^2.0.0: +read-only-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" + readable-stream "^2.0.2" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: - load-json-file "^2.0.0" + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" normalize-package-data "^2.3.2" - path-type "^2.0.0" + path-type "^1.0.0" + +"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.0.27-1, readable-stream@^1.1.13-1, readable-stream@~1.1.11, readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6, readable-stream@^2.3.3: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -2160,14 +2944,52 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" +readable-stream@~1.0.17, readable-stream@~1.0.27-1: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-wrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/readable-wrap/-/readable-wrap-1.0.0.tgz#3b5a211c631e12303a54991c806c17e7ae206bff" + dependencies: + readable-stream "^1.1.13-1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" regenerate@^1.2.1: version "1.3.3" @@ -2185,12 +3007,6 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" 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" - dependencies: - is-equal-shallow "^0.1.3" - regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -2209,72 +3025,80 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" +request@^2.45.0, request@^2.81.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" + aws-sign2 "~0.7.0" + aws4 "^1.6.0" caseless "~0.12.0" combined-stream "~1.0.5" - extend "~3.0.0" + extend "~3.0.1" forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" tunnel-agent "^0.6.0" - uuid "^3.0.0" + uuid "^3.1.0" -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" -require-main-filename@^1.0.1: +resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.3.2: +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" +resolve@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: - align-text "^0.1.1" + exit-hook "^1.0.0" + onetime "^1.0.0" -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +rimraf@^2.2.8: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -2287,75 +3111,120 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +run-parallel@^1.1.2: + version "1.1.6" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +sax@0.1.x: + version "0.1.5" + resolved "https://registry.yarnpkg.com/sax/-/sax-0.1.5.tgz#d1829a6120fa01665eb4dbff6c43f29fd6d61471" -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" -set-immediate-shim@^1.0.1: +server-destroy@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.9" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.9.tgz#98f64880474b74f4a38b8da9d3c0f2d104633e7d" +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: + version "2.4.10" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" dependencies: - shebang-regex "^1.0.0" + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" +shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +shelljs@^0.7.5: + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +single-line-log@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" + dependencies: + string-width "^1.0.1" + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +snazzy@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/snazzy/-/snazzy-7.0.0.tgz#95edaccc4a8d6f80f4ac5cc7b520e8f8f9ac2325" dependencies: - hoek "2.x.x" + chalk "^1.1.0" + inherits "^2.0.1" + minimist "^1.1.1" + readable-stream "^2.0.6" + standard-json "^1.0.0" + text-table "^0.2.0" -source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" -source-map-support@^0.4.15: +source-map-support@^0.4.0, source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" -source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: +source-map@^0.5.6, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -2370,6 +3239,30 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" +speedometer@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" + +split@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/split/-/split-0.1.2.tgz#f0710744c453d551fc7143ead983da6014e336cc" + dependencies: + through "1" + +split@~0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sprintf@~0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/sprintf/-/sprintf-0.1.5.tgz#8f83e39a9317c1a502cb7db8050e51c679f6edcf" + sshpk@^1.7.0: version "1.13.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" @@ -2384,24 +3277,88 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -stream-browserify@^2.0.1: +standard-engine@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-7.0.0.tgz#ebb77b9c8fc2c8165ffa353bd91ba0dff41af690" + dependencies: + deglob "^2.1.0" + get-stdin "^5.0.1" + minimist "^1.1.0" + pkg-conf "^2.0.0" + +standard-json@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/standard-json/-/standard-json-1.0.2.tgz#82dea4a14c78cd9e35d38cde4b88ac6b62596a23" + dependencies: + concat-stream "^1.5.0" + +standard@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/standard/-/standard-10.0.3.tgz#7869bcbf422bdeeaab689a1ffb1fea9677dd50ea" + dependencies: + eslint "~3.19.0" + eslint-config-standard "10.2.1" + eslint-config-standard-jsx "4.0.2" + eslint-plugin-import "~2.2.0" + eslint-plugin-node "~4.2.2" + eslint-plugin-promise "~3.5.0" + eslint-plugin-react "~6.10.0" + eslint-plugin-standard "~3.0.1" + standard-engine "~7.0.0" + +"statuses@>= 1.3.1 < 2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stream-browserify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" dependencies: inherits "~2.0.1" readable-stream "^2.0.2" -stream-http@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-http@^2.0.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.2.6" + readable-stream "^2.3.3" to-arraybuffer "^1.0.0" xtend "^4.0.0" -string-width@^1.0.1, string-width@^1.0.2: +stream-read@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/stream-read/-/stream-read-1.1.2.tgz#3137110d7aa80ba54e4b829c4cd33ca106b9564d" + dependencies: + dezalgo "^1.0.1" + +stream-splicer@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-1.3.2.tgz#3c0441be15b9bf4e226275e6dc83964745546661" + dependencies: + indexof "0.0.1" + inherits "^2.0.1" + isarray "~0.0.1" + readable-stream "^1.1.13-1" + readable-wrap "^1.0.0" + through2 "^1.0.0" + +stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -2416,17 +3373,29 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^1.0.0, string_decoder@~1.0.3: +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.0, string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: +stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: +strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -2438,58 +3407,180 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +sumchecker@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-1.3.1.tgz#79bb3b4456dd04f18ebdbc0d703a1d1daec5105d" + dependencies: + debug "^2.2.0" + es6-promise "^4.0.5" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^4.0.0, supports-color@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" +syntax-error@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.3.0.tgz#1ed9266c4d40be75dc55bf9bb1cb77062bb96ca1" dependencies: - has-flag "^2.0.0" + acorn "^4.0.3" -tapable@^0.2.7: - version "0.2.8" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" +tap-parser@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-0.2.1.tgz#8e1e823f2114ee21d032e2f31e4fb642a296f50b" dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" + split "~0.1.2" -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" +tap-parser@~0.4.0: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-0.4.3.tgz#a4eae190c10d76c7a111921ff38bbe4d58f09eea" dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" + inherits "~2.0.1" + readable-stream "~1.1.11" -timers-browserify@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6" +tape-run@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tape-run/-/tape-run-3.0.2.tgz#fbad4b77b72bab77c36e5f1c3610bfa17402c46d" + dependencies: + "@juliangruber/tap-finished" "0.0.2" + browser-run "^4.1.1" + optimist "~0.6.1" + through "~2.3.4" + throughout "0.0.0" + +tape@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.8.0.tgz#f6a9fec41cc50a1de50fa33603ab580991f6068e" + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.2" + function-bind "~1.1.0" + glob "~7.1.2" + has "~1.0.1" + inherits "~2.0.3" + minimist "~1.2.0" + object-inspect "~1.3.0" + resolve "~1.4.0" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + +tape@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-2.3.3.tgz#2e7ce0a31df09f8d6851664a71842e0ca5057af7" dependencies: - setimmediate "^1.0.4" + deep-equal "~0.1.0" + defined "~0.0.0" + inherits "~2.0.1" + jsonify "~0.0.0" + resumer "~0.0.0" + through "~2.3.4" + +temp-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + +tempy@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.1.0.tgz#8527413cd07100834fcc9cbb8242be95ba0e1fee" + dependencies: + pify "^2.3.0" + temp-dir "^1.0.0" + unique-string "^1.0.0" + +text-table@^0.2.0, text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +throttleit@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" + +through2@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" + dependencies: + readable-stream ">=1.1.13-1 <1.2.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through2@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" + dependencies: + readable-stream "~1.1.9" + xtend "~2.1.1" + +through2@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" + dependencies: + readable-stream "~1.0.17" + xtend "~2.1.1" + +through@1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/through/-/through-1.1.2.tgz#344a5425a3773314ca7e0eb6512fbafaf76c0bfe" + +through@2, "through@>=2.2.7 <3", through@X.X.X, through@^2.3.6, through@^2.3.8, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +throughout@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/throughout/-/throughout-0.0.0.tgz#da935527231a7944daa60d3ad47a32429af1a8c1" + dependencies: + duplexer "~0.0.2" + through "~2.3.4" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" to-arraybuffer@^1.0.0: version "1.0.1" @@ -2499,58 +3590,40 @@ 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" -tough-cookie@~2.3.0: +topo@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5" + dependencies: + hoek "2.x.x" + +tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -ts-loader@^2.1.0: - version "2.3.7" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-2.3.7.tgz#a9028ced473bee12f28a75f9c5b139979d33f2fc" - dependencies: - chalk "^2.0.1" - enhanced-resolve "^3.0.0" - loader-utils "^1.0.2" - semver "^5.0.1" - -tslib@^1.7.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac" - -tslint-config-prettier@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.6.0.tgz#fec1ee8fb07e8f033c63fed6b135af997f31962a" - -tslint@^5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13" +trumpet@^1.7.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/trumpet/-/trumpet-1.7.2.tgz#b02c69e465d171f55e44924bf9b5bdd20974c830" dependencies: - babel-code-frame "^6.22.0" - builtin-modules "^1.1.1" - chalk "^2.1.0" - commander "^2.9.0" - diff "^3.2.0" - glob "^7.1.1" - minimatch "^3.0.4" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.7.1" - tsutils "^2.12.1" + duplexer2 "~0.0.2" + html-select "^2.3.5" + html-tokenize "^1.1.1" + inherits "^2.0.0" + readable-stream "^1.0.27-1" + through2 "^1.0.0" -tsutils@^2.12.1: - version "2.13.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.13.0.tgz#0f52b6aabbc4216e72796b66db028c6cf173e144" - dependencies: - tslib "^1.7.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" +tty-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" tunnel-agent@^0.6.0: version "0.6.0" @@ -2562,55 +3635,71 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" -typescript@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" -uglify-js@^2.8.29: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" +type-is@~1.6.15: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" + media-typer "0.3.0" + mime-types "~2.1.15" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -uglifyjs-webpack-plugin@^0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" +umd@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" dependencies: - source-map "^0.5.6" - uglify-js "^2.8.29" - webpack-sources "^1.0.1" + crypto-random-string "^1.0.0" -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +url-join@^2.0.2: + version "2.0.5" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" -url@^0.11.0: +url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: punycode "1.3.2" querystring "0.2.0" +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util@0.10.3, util@^0.10.3: +util@0.10.3, util@~0.10.1: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: inherits "2.0.1" -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" +uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" validate-npm-package-license@^3.0.1: version "3.0.1" @@ -2627,130 +3716,49 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vm-browserify@0.0.4: +vm-browserify@~0.0.1: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" dependencies: indexof "0.0.1" -watchpack@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" - dependencies: - async "^2.1.2" - chokidar "^1.7.0" - graceful-fs "^4.1.2" - -webpack-sources@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" -webpack@^3.8.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" - dependencies: - acorn "^5.0.0" - acorn-dynamic-import "^2.0.0" - ajv "^5.1.5" - ajv-keywords "^2.0.0" - async "^2.1.2" - enhanced-resolve "^3.4.0" - escope "^3.6.0" - interpret "^1.0.0" - json-loader "^0.5.4" - json5 "^0.5.1" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - mkdirp "~0.5.0" - node-libs-browser "^2.0.0" - source-map "^0.5.3" - supports-color "^4.2.1" - tapable "^0.2.7" - uglifyjs-webpack-plugin "^0.4.6" - watchpack "^1.4.0" - webpack-sources "^1.0.1" - yargs "^8.0.2" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - dependencies: - isexe "^2.0.0" +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: - string-width "^1.0.2" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + mkdirp "^0.5.1" -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" +xhr-write-stream@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/xhr-write-stream/-/xhr-write-stream-0.1.2.tgz#e357848e0d039b411fdd5b3bf81be47ee5ce26aa" dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" + concat-stream "~0.1.0" + ordered-emitter "~0.1.0" -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -xtend@^4.0.0: +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - -yallist@^2.1.2: +xtend@~2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - dependencies: - camelcase "^4.1.0" - -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" + fd-slicer "~1.0.1" From b346f51f224529a6cf6352c348b9777a5fd4d7f6 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Feb 2018 19:26:27 +0000 Subject: [PATCH 02/99] tests passing up to and including added to room hook --- package.json | 17 +- react-native.js | 2 +- rollup/web.js | 44 +++ src/chat-manager.js | 59 ++++ src/current-user.js | 62 ++++ src/main.js | 4 + src/token-provider.js | 29 ++ src/utils.js | 38 +++ tests/main.js | 137 ++++---- worker.js | 2 +- yarn.lock | 722 ++++++++++++++++++++++++++++++++++++++++-- 11 files changed, 1009 insertions(+), 107 deletions(-) create mode 100644 rollup/web.js create mode 100644 src/chat-manager.js create mode 100644 src/current-user.js create mode 100644 src/main.js create mode 100644 src/token-provider.js create mode 100644 src/utils.js diff --git a/package.json b/package.json index 1006d0d..9290a3e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,11 @@ "pusher-platform": "^0.14.0" }, "devDependencies": { + "babel-cli": "^6.26.0", "babel-core": "^6.26.0", + "babel-eslint": "^7.0.0", + "babel-plugin-external-helpers": "^6.22.0", + "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-preset-env": "^1.6.1", "babelify": "^8.0.0", @@ -26,16 +30,23 @@ "faucet": "^0.0.1", "pusher-chatkit-server": "^0.9.1", "ramda": "^0.25.0", + "rollup": "^0.55.3", + "rollup-plugin-babel": "^3.0.3", + "rollup-plugin-commonjs": "^8.3.0", + "rollup-plugin-node-resolve": "^3.0.2", "snazzy": "^7.0.0", "standard": "^10.0.3", "tape": "^4.8.0", "tape-run": "^3.0.2" }, "scripts": { - "build": "echo ...", - "lint": "standard --verbose tests | snazzy", + "lint": "standard --parser babel-eslint --verbose | snazzy", + "build": "yarn build:all", + "build:all": "yarn build:web", + "build:web": "rollup -c rollup/web.js", "test": "browserify tests/main.js -t babelify | tape-run | faucet", - "lint:test": "clear && yarn lint && clear && yarn test" + "lint:build": "clear && yarn lint && clear && yarn build", + "lint:build:test": "yarn lint:build && clear && yarn test" }, "babel": { "presets": [ diff --git a/react-native.js b/react-native.js index b8e4d53..552022b 100644 --- a/react-native.js +++ b/react-native.js @@ -1 +1 @@ -module.exports = require('./dist/react-native/chatkit'); +module.exports = require('./dist/react-native/chatkit') diff --git a/rollup/web.js b/rollup/web.js new file mode 100644 index 0000000..dea7fa1 --- /dev/null +++ b/rollup/web.js @@ -0,0 +1,44 @@ +import babel from 'rollup-plugin-babel' +import commonjs from 'rollup-plugin-commonjs' +import resolve from 'rollup-plugin-node-resolve' + +export default { + input: 'src/main.js', + output: { + file: 'dist/web/chatkit.js', + format: 'umd', + name: 'Chatkit' + }, + plugins: [ + babel({ + babelrc: false, + presets: [ + [ + 'env', + { + modules: false + } + ] + ], + plugins: [ + 'external-helpers', + 'transform-class-properties', + 'transform-object-rest-spread' + ], + exclude: [ + 'node_modules/**' + ] + }), + resolve(), + commonjs({ + namedExports: { + 'node_modules/pusher-platform/dist/web/pusher-platform.js': [ + 'BaseClient', + 'HOST_BASE', + 'Instance', + 'sendRawRequest' + ] + } + }) + ] +} diff --git a/src/chat-manager.js b/src/chat-manager.js new file mode 100644 index 0000000..01a90cb --- /dev/null +++ b/src/chat-manager.js @@ -0,0 +1,59 @@ +import { BaseClient, HOST_BASE, Instance } from 'pusher-platform' +import { split } from 'ramda' + +import { CurrentUser } from './current-user' +import { typeCheck, typeCheckObj } from './utils' + +export class ChatManager { + // TODO accept a tokenProviderUrl and create a default tokenProvider? + constructor ({ instanceLocator, tokenProvider, userId, ...options } = {}) { + typeCheck('instanceLocator', 'string', instanceLocator) + typeCheck('tokenProvider', 'object', tokenProvider) + typeCheck('tokenProvider.fetchToken', 'function', tokenProvider.fetchToken) + typeCheck('userId', 'string', userId) + const cluster = split(':', instanceLocator)[1] + if (cluster === undefined) { + throw new TypeError( + `expected instanceLocator to be of the format x:y:z, but was ${instanceLocator}` + ) + } + const baseClient = options.baseClient || new BaseClient({ + host: `${cluster}.${HOST_BASE}`, + logger: options.logger + }) + if (typeof tokenProvider.setUserId === 'function') { + tokenProvider.setUserId(userId) + } + const instanceOptions = { + client: baseClient, + locator: instanceLocator, + logger: options.logger, + tokenProvider + } + this.apiInstance = new Instance({ + serviceName: 'chatkit', + serviceVersion: 'v1', + ...instanceOptions + }) + this.filesInstance = new Instance({ + serviceName: 'chatkit_files', + serviceVersion: 'v1', + ...instanceOptions + }) + this.cursorsInstance = new Instance({ + serviceName: 'chatkit_cursors', + serviceVersion: 'v1', + ...instanceOptions + }) + } + + connect (hooks = {}) { + typeCheckObj('function', hooks) + const currentUser = new CurrentUser({ + apiInstance: this.apiInstance + }) + return Promise.all([ + currentUser.establishUserSubscription(hooks) + ]).then(() => currentUser) + } +} diff --git a/src/current-user.js b/src/current-user.js new file mode 100644 index 0000000..778c5b4 --- /dev/null +++ b/src/current-user.js @@ -0,0 +1,62 @@ +import { append, map } from 'ramda' + +const parseRoom = data => ({ + createdAt: data.created_at, + createdByUserId: data.created_by_id, + deletedAt: data.deletedAt, + id: data.id, + isPrivate: data.private, + name: data.name, + updatedAt: data.updated_at, + userIds: data.member_user_ids +}) + +export class CurrentUser { + constructor ({ apiInstance }) { + this.apiInstance = apiInstance + } + + /* public */ + + /* internal */ + establishUserSubscription = hooks => new Promise((resolve, reject) => + this.apiInstance.subscribeNonResuming({ + path: '/users', + listeners: { + onError: reject, + onEvent: this.onEvent({ + ...hooks, + subscriptionEstablished: resolve + }) + } + }) + ) + + onEvent = hooks => ({ body }) => { + switch (body.event_name) { + case 'initial_state': + this.onInitialState(body.data) + if (hooks.subscriptionEstablished) { + hooks.subscriptionEstablished() + } + break + case 'added_to_room': + const room = parseRoom(body.data.room) + this.rooms = append(room, this.rooms) + if (hooks.addedToRoom) { + hooks.addedToRoom(room) + } + break + } + } + + onInitialState = ({ current_user: currentUser, rooms }) => { + this.avatarURL = currentUser.avatar_url + this.createdAt = currentUser.created_at + this.customData = currentUser.custom_data + this.id = currentUser.id + this.name = currentUser.name + this.updatedAt = currentUser.updated_at + this.rooms = map(parseRoom, rooms) + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..7e62a2e --- /dev/null +++ b/src/main.js @@ -0,0 +1,4 @@ +import { TokenProvider } from './token-provider' +import { ChatManager } from './chat-manager' + +export default { TokenProvider, ChatManager } diff --git a/src/token-provider.js b/src/token-provider.js new file mode 100644 index 0000000..2c8c97c --- /dev/null +++ b/src/token-provider.js @@ -0,0 +1,29 @@ +import { sendRawRequest } from 'pusher-platform' + +import { urlEncode, appendQueryParam, typeCheck } from './utils' + +export class TokenProvider { + // TODO authContext + constructor ({ url } = {}) { + typeCheck('url', 'string', url) + this.url = url + } + + // TODO caching + fetchToken () { + return sendRawRequest({ + body: urlEncode({ grant_type: 'client_credentials' }), + headers: { + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + url: appendQueryParam('user_id', this.userId, this.url) + }).then(res => JSON.parse(res).access_token) + } + + // To allow ChatManager to feed the userId to the TokenProvider. Not set + // directly so as not to mess with a custom TokenProvider implementation. + setUserId (userId) { + this.userId = userId + } +} diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..bd9e154 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,38 @@ +import { + filter, + forEachObjIndexed, + join, + map, + pipe, + split, + toPairs +} from 'ramda' + +// urlEncode :: Object -> String +export const urlEncode = pipe( + filter(x => x !== undefined), + toPairs, + map(([k, v]) => `${k}=${encodeURIComponent(v)}`), + join('&') +) + +// appendQueryParam :: String -> String -> String -> String +export const appendQueryParam = (key, value, url) => { + const [ beforeQ, afterQ ] = split('?', url) + return beforeQ + '?' + (afterQ ? afterQ + '&' : '') + urlEncode({ [key]: value }) +} + +export const typeCheck = (name, expectedType, value) => { + const type = typeof value + if (type !== expectedType) { + throw new TypeError( + `expected ${name} to be of type ${expectedType} but was of type ${type}` + ) + } +} + +// checks that all of an objects values are of the given type +export const typeCheckObj = (expectedType, obj) => forEachObjIndexed( + (value, key) => typeCheck(key, expectedType, value), + obj +) diff --git a/tests/main.js b/tests/main.js index b0e67b6..3885a9b 100644 --- a/tests/main.js +++ b/tests/main.js @@ -1,7 +1,9 @@ import test from 'tape' import { + any, compose, concat, + curry, find, head, map, @@ -61,21 +63,13 @@ const batch = (n, f) => { const concatBatch = (n, f) => batch(n, compose(f, reduce(concat, []))) -const fetchUser = (t, userId, hooks = {}) => new Promise(resolve => { - new ChatManager({ - instanceLocator: INSTANCE_LOCATOR, - userId, - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) - }).connect({ - onSuccess: resolve, - onError: endWithErr(t), - // Fire any hooks at most once, so that they don't interfere with later - // tests. - delegate: map(once, hooks) - }) -}) +const fetchUser = (t, userId, hooks = {}) => new ChatManager({ + instanceLocator: INSTANCE_LOCATOR, + userId, + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) +}).connect(map(once, hooks)).catch(endWithErr(t)) -const endWithErr = t => err => t.end(`error: ${toString(err)}`) +const endWithErr = curry((t, err) => t.end(`error: ${toString(err)}`)) const sendMessage = (user, room, text) => new Promise((resolve, reject) => user.sendMessage({ roomId: room.id, text }, resolve, reject)) @@ -106,8 +100,7 @@ test('instantiate TokenProvider with url', t => { t.end() }) -// FIXME -test.skip('instantiate TokenProvider with non-string url fails', t => { +test('instantiate TokenProvider with non-string url fails', t => { t.throws(() => new TokenProvider({ url: 42 }), /url/) t.end() }) @@ -115,11 +108,13 @@ test.skip('instantiate TokenProvider with non-string url fails', t => { // Chat manager test('instantiate ChatManager with correct params', t => { - t.equal(typeof new ChatManager({ + const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) - }), 'object') + }) + t.equal(typeof chatManager, 'object') + t.equal(typeof chatManager.connect, 'function') t.end() }) @@ -141,8 +136,7 @@ test('instantiate ChatManager without userId fails', t => { t.end() }) -// FIXME -test.skip('instantiate ChatManager with non-string userId fails', t => { +test('instantiate ChatManager with non-string userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -151,8 +145,7 @@ test.skip('instantiate ChatManager with non-string userId fails', t => { t.end() }) -// FIXME -test.skip('instantiate ChatManager with non tokenProvider fails', t => { +test('instantiate ChatManager with non tokenProvider fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -161,28 +154,17 @@ test.skip('instantiate ChatManager with non tokenProvider fails', t => { t.end() }) -// FIXME -test.skip('connection fails if provided with non-function hooks', t => { - // onError actually does get called, but only as a result of the user not - // existing, the hooks (currently delegate) should be checked client side +test('connection fails if provided with non-function hooks', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }) - chatManager.connect({ - delegates: { - nonFunction: 42 - }, - onSuccess: () => { - t.end('onsuccess should not be called') - }, - onError: err => { - t.true(toString(err).match(/nonFunction/), 'nonFunction error') - t.end() - } - }) - t.timeoutAfter(TEST_TIMEOUT) + t.throws( + () => chatManager.connect({ nonFunction: 42 }), + /nonFunction/ + ) + t.end() }) test('connection fails for nonexistent user', t => { @@ -191,18 +173,17 @@ test('connection fails for nonexistent user', t => { userId: 'alice', tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }) - chatManager.connect({ - onSuccess: () => { - t.end('onSuccess should not be called') - }, - onError: err => { + chatManager.connect() + .then(() => { + t.end('promise should not resolve') + }) + .catch(err => { t.true( toString(err).match(/user does not exist/), 'user does not exist error' ) t.end() - } - }) + }) t.timeoutAfter(TEST_TIMEOUT) }) @@ -222,6 +203,7 @@ test('connection resolves with current user object', t => { t.equal(typeof user, 'object') t.equal(user.id, 'alice') t.equal(user.name, 'Alice') + t.true(Array.isArray(user.rooms), 'user.rooms is an array') t.equal(user.rooms.length, 1) t.equal(user.rooms[0].name, `Alice's room`) t.equal(user.rooms[0].isPrivate, false) @@ -235,12 +217,15 @@ test('connection resolves with current user object', t => { // User subscription test(`added to room hook [creates Bob & Bob's room]`, t => { + let alice fetchUser(t, 'alice', { addedToRoom: room => { t.equal(room.name, `Bob's room`) + t.true(any(r => r.id === room.id, alice.rooms), `should contain Bob's room`) t.end() } }) + .then(a => { alice = a }) .then(() => server.createUser('bob', 'Bob')) .then(() => server.createRoom('bob', { name: `Bob's room`, @@ -254,7 +239,7 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { // This test has to run before any tests which cause Bob to open a subscription // (since then he will already be online) -test('user came online hook (user sub)', t => { +test.skip('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') @@ -270,7 +255,7 @@ test('user came online hook (user sub)', t => { // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. -test('typing indicators (user sub)', t => { +test.skip('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { @@ -295,7 +280,7 @@ test('typing indicators (user sub)', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('user left room hook (user sub) [removes Bob from his own room]', t => { +test.skip('user left room hook (user sub) [removes Bob from his own room]', t => { fetchUser(t, 'alice', { userLeftRoom: (room, user) => { t.equal(room.id, bobsRoom.id) @@ -311,7 +296,7 @@ test('user left room hook (user sub) [removes Bob from his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('user joined room hook (user sub) [Bob rejoins his own room]', t => { +test.skip('user joined room hook (user sub) [Bob rejoins his own room]', t => { fetchUser(t, 'alice', { userJoinedRoom: (room, user) => { t.equal(room.id, bobsRoom.id) @@ -327,7 +312,7 @@ test('user joined room hook (user sub) [Bob rejoins his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('room updated hook', t => { +test.skip('room updated hook', t => { fetchUser(t, 'alice', { roomUpdated: room => { t.equal(room.id, bobsRoom.id) @@ -343,7 +328,7 @@ test('room updated hook', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`removed from room hook [removes Alice from Bob's room]`, t => { +test.skip(`removed from room hook [removes Alice from Bob's room]`, t => { fetchUser(t, 'alice', { removedFromRoom: room => { t.equal(room.id, bobsRoom.id) @@ -360,7 +345,7 @@ test(`removed from room hook [removes Alice from Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`room deleted hook [destroys Alice's room]`, t => { +test.skip(`room deleted hook [destroys Alice's room]`, t => { fetchUser(t, 'alice', { roomDeleted: room => { t.equal(room.id, alicesRoom.id) @@ -376,7 +361,7 @@ test(`room deleted hook [destroys Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create room [creates Alice's new room]`, t => { +test.skip(`create room [creates Alice's new room]`, t => { fetchUser(t, 'alice').then(alice => alice.createRoom( { name: `Alice's new room` }, room => { @@ -392,7 +377,7 @@ test(`create room [creates Alice's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create private room [creates Alice's private room]`, t => { +test.skip(`create private room [creates Alice's private room]`, t => { fetchUser(t, 'alice').then(alice => alice.createRoom( { name: `Alice's private room`, private: true }, room => { @@ -408,7 +393,7 @@ test(`create private room [creates Alice's private room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create room with members [creates Bob's new room]`, t => { +test.skip(`create room with members [creates Bob's new room]`, t => { fetchUser(t, 'bob').then(bob => bob.createRoom( { name: `Bob's new room`, addUserIds: ['alice'] }, room => { @@ -424,7 +409,7 @@ test(`create room with members [creates Bob's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('get joined rooms', t => { +test.skip('get joined rooms', t => { const expectedRoomIds = [alicesRoom, bobsRoom, alicesPrivateRoom] .map(r => r.id).sort() fetchUser(t, 'alice').then(alice => alice.getJoinedRooms( @@ -437,7 +422,7 @@ test('get joined rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('get joinable rooms', t => { +test.skip('get joinable rooms', t => { fetchUser(t, 'bob').then(bob => bob.getJoinableRooms( rooms => { const ids = rooms.map(r => r.id) @@ -475,7 +460,7 @@ test.skip('get all rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`join room [Bob joins Alice's room]`, t => { +test.skip(`join room [Bob joins Alice's room]`, t => { fetchUser(t, 'bob').then(bob => bob.joinRoom( alicesRoom.id, room => { @@ -483,7 +468,7 @@ test(`join room [Bob joins Alice's room]`, t => { t.equal(room.createdByUserId, 'alice') t.true(room.userIds.includes('bob'), 'should include bob') t.true( - bob.rooms.some(r => r.id === alicesRoom.id), + any(r => r.id === alicesRoom.id, bob.rooms), `should include Alice's room` ) t.end() @@ -493,12 +478,12 @@ test(`join room [Bob joins Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`leave room [Bob leaves Alice's room]`, t => { +test.skip(`leave room [Bob leaves Alice's room]`, t => { fetchUser(t, 'bob').then(bob => bob.leaveRoom( alicesRoom.id, () => setTimeout(() => { t.false( - bob.rooms.some(r => r.id === alicesRoom.id), + any(r => r.id === alicesRoom.id, bob.rooms), `shouldn't include Alice's room` ) t.end() @@ -508,7 +493,7 @@ test(`leave room [Bob leaves Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('add user [Alice adds Bob to her room]', t => { +test.skip('add user [Alice adds Bob to her room]', t => { fetchUser(t, 'alice').then(alice => alice.addUser( 'bob', alicesRoom.id, @@ -522,7 +507,7 @@ test('add user [Alice adds Bob to her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('remove user [Alice removes Bob from her room]', t => { +test.skip('remove user [Alice removes Bob from her room]', t => { fetchUser(t, 'alice').then(alice => alice.removeUser( 'bob', alicesRoom.id, @@ -536,7 +521,7 @@ test('remove user [Alice removes Bob from her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`send message [sends four messages to Bob's room]`, t => { +test.skip(`send message [sends four messages to Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => sendMessages(alice, bobsRoom, [ 'hello', 'hey', 'hi', 'ho' @@ -546,7 +531,7 @@ test(`send message [sends four messages to Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('fetch messages', t => { +test.skip('fetch messages', t => { fetchUser(t, 'alice').then(alice => alice.fetchMessagesFromRoom( bobsRoom, // TODO why is this room, and send message etc is roomId? {}, @@ -563,7 +548,7 @@ test('fetch messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('fetch messages with pagination', t => { +test.skip('fetch messages with pagination', t => { fetchUser(t, 'alice') .then(alice => new Promise(resolve => { alice.fetchMessagesFromRoom( @@ -590,7 +575,7 @@ test('fetch messages with pagination', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and fetch initial messages', t => { +test.skip('subscribe to room and fetch initial messages', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( find(r => r.id === bobsRoom.id, alice.rooms), { @@ -603,7 +588,7 @@ test('subscribe to room and fetch initial messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and fetch last two message only', t => { +test.skip('subscribe to room and fetch last two message only', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( find(r => r.id === bobsRoom.id, alice.rooms), { @@ -617,7 +602,7 @@ test('subscribe to room and fetch last two message only', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and receive sent messages', t => { +test.skip('subscribe to room and receive sent messages', t => { fetchUser(t, 'alice').then(alice => { alice.subscribeToRoom( find(r => r.id === bobsRoom.id, alice.rooms), @@ -634,12 +619,12 @@ test('subscribe to room and receive sent messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('[setup] create Carol', t => server.createUser('carol', 'Carol') +test.skip('[setup] create Carol', t => server.createUser('carol', 'Carol') .then(() => t.end()) .catch(endWithErr(t)) ) -test(`user joined hook [Carol joins Bob's room]`, t => { +test.skip(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => { alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { @@ -661,7 +646,7 @@ test(`user joined hook [Carol joins Bob's room]`, t => { // This test has to run before any tests which cause Carol to open a // subscription (since then she will already be online) -test('user came online hook', t => { +test.skip('user came online hook', t => { fetchUser(t, 'alice') .then(alice => { alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { @@ -682,7 +667,7 @@ test('user came online hook', t => { // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. -test('typing indicators', t => { +test.skip('typing indicators', t => { let started Promise.all([ fetchUser(t, 'alice').then(alice => { @@ -710,7 +695,7 @@ test('typing indicators', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`user left hook [removes Carol from Bob's room]`, t => { +test.skip(`user left hook [removes Carol from Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => { alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { @@ -764,7 +749,7 @@ test.skip('non-admin delete room fails gracefully', t => { // TODO read cursors (perhaps reconsider interface) -test('[teardown] destroy Carol', t => { +test.skip('[teardown] destroy Carol', t => { server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) t.timeoutAfter(TEST_TIMEOUT) }) diff --git a/worker.js b/worker.js index 16406e9..16d0e4e 100644 --- a/worker.js +++ b/worker.js @@ -1 +1 @@ -module.exports = require('./dist/worker/chatkit.worker'); +module.exports = require('./dist/worker/chatkit.worker') diff --git a/yarn.lock b/yarn.lock index c84130b..34620ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,6 +27,10 @@ JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -49,7 +53,7 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.7.0: +ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: @@ -81,12 +85,40 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" @@ -113,6 +145,10 @@ array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + array.prototype.find@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" @@ -144,6 +180,10 @@ assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + assert@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" @@ -156,19 +196,48 @@ astw@^2.0.0: dependencies: acorn "^4.0.3" +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" -aws4@^1.6.0: +aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -babel-code-frame@^6.16.0, babel-code-frame@^6.26.0: +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -200,6 +269,15 @@ babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" +babel-eslint@^7.0.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" + dependencies: + babel-code-frame "^6.22.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" + babylon "^6.17.0" + babel-generator@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" @@ -326,10 +404,20 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.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: + babel-runtime "^6.22.0" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -350,6 +438,15 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-plugin-transform-es2015-arrow-functions@^6.22.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" @@ -546,6 +643,14 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + babel-preset-env@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" @@ -610,7 +715,7 @@ babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -624,7 +729,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -637,7 +742,7 @@ babelify@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/babelify/-/babelify-8.0.0.tgz#6f60f5f062bfe7695754ef2403b842014a580ed3" -babylon@^6.18.0: +babylon@^6.17.0, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -659,6 +764,16 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -678,6 +793,12 @@ body-parser@^1.17.2: raw-body "2.3.2" type-is "~1.6.15" +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + boom@4.x.x: version "4.3.1" resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" @@ -697,6 +818,14 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -874,7 +1003,7 @@ buffer@^5.0.2: base64-js "^1.0.2" ieee754 "^1.1.4" -builtin-modules@^1.0.0, builtin-modules@^1.1.1: +builtin-modules@^1.0.0, builtin-modules@^1.1.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -929,6 +1058,21 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -982,6 +1126,10 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" +commander@^2.11.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1012,6 +1160,10 @@ console-browserify@^1.1.0: dependencies: date-now "^0.1.4" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -1067,6 +1219,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + cryptiles@3.x.x: version "3.1.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" @@ -1193,6 +1351,10 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" @@ -1223,6 +1385,10 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + detective@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/detective/-/detective-5.0.2.tgz#84ec2e1c581e74211e2ae4ffce1edf52c3263f84" @@ -1600,6 +1766,18 @@ estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" +estree-walker@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e" + +estree-walker@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" + +estree-walker@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.1.tgz#64fc375053abc6f57d73e9bd2f004644ad3c5854" + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -1626,14 +1804,32 @@ exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + extend@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.1.tgz#1ee8010689e7395ff9448241c98652bc759a8260" -extend@~3.0.1: +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + extract-zip@^1.0.3: version "1.6.6" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" @@ -1695,6 +1891,20 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + find-root@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -1727,6 +1937,16 @@ for-each@~0.3.2: dependencies: is-function "~1.0.0" +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -1735,6 +1955,14 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + form-data@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" @@ -1753,14 +1981,55 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-readdir-recursive@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" +fsevents@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.39" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + generate-function@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" @@ -1785,7 +2054,20 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@~7.1.2: +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2, glob@~7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -1811,14 +2093,25 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + har-validator@~5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" @@ -1836,6 +2129,10 @@ has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + has@^1.0.0, has@^1.0.1, has@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" @@ -1862,6 +2159,15 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.0" +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + hawk@~6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" @@ -1951,6 +2257,14 @@ http-errors@1.6.2, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -1996,7 +2310,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -2059,7 +2373,13 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-buffer@^1.1.0: +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.0, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -2077,6 +2397,24 @@ is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" @@ -2097,6 +2435,16 @@ is-function@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + is-my-json-valid@^2.10.0: version "2.17.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" @@ -2106,6 +2454,18 @@ is-my-json-valid@^2.10.0: jsonpointer "^4.0.0" xtend "^4.0.0" +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -2122,6 +2482,14 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -2152,7 +2520,7 @@ isarray@0.0.1, isarray@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2160,6 +2528,12 @@ isemail@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a" +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -2286,6 +2660,18 @@ jws@^3.1.4: jwa "^1.1.4" safe-buffer "^5.0.1" +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" @@ -2368,6 +2754,12 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +magic-string@^0.22.4: + version "0.22.4" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.4.tgz#31039b4e40366395618c1d6cf8193c53917475ff" + dependencies: + vlq "^0.2.1" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -2402,6 +2794,24 @@ merge@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.0.0.tgz#b443ab46d837c491e6222056ab0f7933ecb3568f" +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -2413,7 +2823,7 @@ mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" -mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.17: +mime-types@^2.1.12, mime-types@~2.1.15, 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: @@ -2431,7 +2841,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -2459,7 +2869,7 @@ mkdirp@0.5.0: dependencies: minimist "0.0.8" -mkdirp@^0.5.0, mkdirp@^0.5.1: +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -2509,10 +2919,37 @@ mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +nan@^2.3.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" + dependencies: + detect-libc "^1.0.2" + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" @@ -2522,6 +2959,21 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + nugget@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" @@ -2538,7 +2990,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.2: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -2567,6 +3019,13 @@ object.assign@^4.0.4: has-symbols "^1.0.0" object-keys "^1.0.11" +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -2613,10 +3072,25 @@ os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" -os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" +osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + p-limit@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" @@ -2653,6 +3127,15 @@ parse-asn1@^5.0.0: evp_bytestokey "^1.0.0" pbkdf2 "^3.0.3" +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -2718,6 +3201,10 @@ pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -2787,6 +3274,10 @@ prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + pretty-bytes@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" @@ -2859,6 +3350,10 @@ qs@6.5.1, qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -2871,6 +3366,13 @@ ramda@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" @@ -2902,6 +3404,15 @@ rc@^1.1.2: minimist "^1.2.0" strip-json-comments "~2.0.1" +rc@^1.1.7: + version "1.2.5" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + read-only-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" @@ -2932,7 +3443,7 @@ read-pkg@^1.0.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -2970,6 +3481,15 @@ readable-wrap@^1.0.0: dependencies: readable-stream "^1.1.13-1" +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -2995,6 +3515,10 @@ regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -3007,6 +3531,12 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" 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" + dependencies: + is-equal-shallow "^0.1.3" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -3025,12 +3555,51 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" +request@2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + request@^2.45.0, request@^2.81.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -3073,7 +3642,7 @@ resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7: +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: @@ -3098,7 +3667,7 @@ resumer@~0.0.0: dependencies: through "~2.3.4" -rimraf@^2.2.8: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -3111,6 +3680,48 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" +rollup-plugin-babel@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-3.0.3.tgz#63adedc863130327512a4a9006efc2241c5b7c15" + dependencies: + rollup-pluginutils "^1.5.0" + +rollup-plugin-commonjs@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.3.0.tgz#91b4ba18f340951e39ed7b1901f377a80ab3f9c3" + dependencies: + acorn "^5.2.1" + estree-walker "^0.5.0" + magic-string "^0.22.4" + resolve "^1.4.0" + rollup-pluginutils "^2.0.1" + +rollup-plugin-node-resolve@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.2.tgz#38babc12fd404cc2ba1ff68648fe43fa3ffee6b0" + dependencies: + builtin-modules "^1.1.0" + is-module "^1.0.0" + resolve "^1.1.6" + +rollup-pluginutils@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" + dependencies: + estree-walker "^0.2.1" + minimatch "^3.0.2" + +rollup-pluginutils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz#7ec95b3573f6543a46a6461bd9a7c544525d0fc0" + dependencies: + estree-walker "^0.3.0" + micromatch "^2.3.11" + +rollup@^0.55.3: + version "0.55.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.55.3.tgz#0af082a766d51c3058430c8372442ff5207d8736" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -3145,6 +3756,14 @@ server-destroy@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -3209,6 +3828,12 @@ snazzy@^7.0.0: standard-json "^1.0.0" text-table "^0.2.0" +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + sntp@2.x.x: version "2.1.0" resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" @@ -3358,7 +3983,7 @@ stream-splicer@^2.0.0: inherits "^2.0.1" readable-stream "^2.0.2" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -3391,11 +4016,11 @@ string_decoder@~1.0.0, string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.5: +stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -strip-ansi@^3.0.0: +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -3513,6 +4138,27 @@ tape@~2.3.2: resumer "~0.0.0" through "~2.3.4" +tar-pack@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -3596,7 +4242,7 @@ topo@1.x.x: dependencies: hoek "2.x.x" -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" dependencies: @@ -3652,6 +4298,10 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + umd@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" @@ -3681,6 +4331,10 @@ url@~0.11.0: punycode "1.3.2" querystring "0.2.0" +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -3697,10 +4351,16 @@ util@0.10.3, util@~0.10.1: dependencies: inherits "2.0.1" -uuid@^3.1.0: +uuid@^3.0.0, uuid@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -3716,12 +4376,22 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vlq@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" + vm-browserify@~0.0.1: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" dependencies: indexof "0.0.1" +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" From 7dd6aa28b782a42c91a28db063991ed4c58a38f7 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Feb 2018 19:28:31 +0000 Subject: [PATCH 03/99] removed .prettierrc --- .prettierrc | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 3e9d085..0000000 --- a/.prettierrc +++ /dev/null @@ -1,2 +0,0 @@ -singleQuote: true -trailingComma: all From f1d5976e84ff92bc433ee3ab6e443ff52c62a6ef Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 6 Feb 2018 16:58:32 +0000 Subject: [PATCH 04/99] basic user and presence store --- package.json | 1 + src/chat-manager.js | 5 ++ src/current-user.js | 108 ++++++++++++++++++++++++++++++++++++-------- src/parsers.js | 30 ++++++++++++ src/room.js | 17 +++++++ src/store.js | 22 +++++++++ src/user-store.js | 38 ++++++++++++++++ src/utils.js | 4 +- tests/main.js | 51 ++++++++++++++------- yarn.lock | 27 +++++++++++ 10 files changed, 266 insertions(+), 37 deletions(-) create mode 100644 src/parsers.js create mode 100644 src/room.js create mode 100644 src/store.js create mode 100644 src/user-store.js diff --git a/package.json b/package.json index 9290a3e..91953e3 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "snazzy": "^7.0.0", "standard": "^10.0.3", "tape": "^4.8.0", + "tape-catch": "^1.0.6", "tape-run": "^3.0.2" }, "scripts": { diff --git a/src/chat-manager.js b/src/chat-manager.js index 01a90cb..f554ef5 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -45,15 +45,20 @@ export class ChatManager { serviceVersion: 'v1', ...instanceOptions }) + this.userId = userId } connect (hooks = {}) { typeCheckObj('function', hooks) const currentUser = new CurrentUser({ + id: this.userId, apiInstance: this.apiInstance }) return Promise.all([ currentUser.establishUserSubscription(hooks) + .then(currentUser.initializeUserStore), + currentUser.establishPresenceSubscription(hooks) + // currentUser.initializeCursorStore() ]).then(() => currentUser) } } diff --git a/src/current-user.js b/src/current-user.js index 778c5b4..c8acf25 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,19 +1,32 @@ -import { append, map } from 'ramda' - -const parseRoom = data => ({ - createdAt: data.created_at, - createdByUserId: data.created_by_id, - deletedAt: data.deletedAt, - id: data.id, - isPrivate: data.private, - name: data.name, - updatedAt: data.updated_at, - userIds: data.member_user_ids -}) +import { + append, + chain, + compose, + join, + length, + map, + pipe, + prop, + reduce, + uniq +} from 'ramda' + +import { appendQueryParam } from './utils' +import { Store } from './store' +import { UserStore } from './user-store' +import { parseUser, parseRoom, parsePresenceState } from './parsers' export class CurrentUser { - constructor ({ apiInstance }) { + constructor ({ id, apiInstance }) { + this.id = id this.apiInstance = apiInstance + this.logger = apiInstance.logger + this.presenceStore = new Store() + this.userStore = new UserStore({ + apiInstance, + presenceStore: this.presenceStore, + logger: this.logger + }) } /* public */ @@ -24,7 +37,7 @@ export class CurrentUser { path: '/users', listeners: { onError: reject, - onEvent: this.onEvent({ + onEvent: this.onUserEvent({ ...hooks, subscriptionEstablished: resolve }) @@ -32,16 +45,17 @@ export class CurrentUser { }) ) - onEvent = hooks => ({ body }) => { + onUserEvent = hooks => ({ body }) => { switch (body.event_name) { case 'initial_state': - this.onInitialState(body.data) + this.onUserInitialState(body.data) if (hooks.subscriptionEstablished) { hooks.subscriptionEstablished() } break case 'added_to_room': - const room = parseRoom(body.data.room) + // TODO fetch new user details in bulk when added to room (etc) + const room = parseRoom(this.userStore, body.data.room) this.rooms = append(room, this.rooms) if (hooks.addedToRoom) { hooks.addedToRoom(room) @@ -50,13 +64,69 @@ export class CurrentUser { } } - onInitialState = ({ current_user: currentUser, rooms }) => { + onUserInitialState = ({ current_user: currentUser, rooms }) => { this.avatarURL = currentUser.avatar_url this.createdAt = currentUser.created_at this.customData = currentUser.custom_data this.id = currentUser.id this.name = currentUser.name this.updatedAt = currentUser.updated_at - this.rooms = map(parseRoom, rooms) + this.rooms = map(parseRoom(this.userStore), rooms) + } + + establishPresenceSubscription = hooks => new Promise((resolve, reject) => + this.apiInstance.subscribeNonResuming({ + path: `/users/${this.id}/presence`, + listeners: { + onError: reject, + onEvent: this.onPresenceEvent({ + ...hooks, + subscriptionEstablished: resolve + }) + } + }) + ) + + onPresenceEvent = hooks => ({ body }) => { + switch (body.event_name) { + case 'initial_state': + this.onPresenceInitialState(body.data) + if (hooks.subscriptionEstablished) { + hooks.subscriptionEstablished() + } + break + } + } + + onPresenceInitialState = ({ user_states: userStates }) => { + compose( + this.presenceStore.initialize, + reduce((acc, state) => ({ ...acc, [state.userId]: state }), {}), + map(parsePresenceState) + )(userStates) + } + + initializeUserStore = () => { + const userIds = uniq(chain(prop('userIds'), this.rooms)) + if (length(userIds) === 0) { + this.userStore.initialize({}) + return + } + return this.apiInstance + .request({ + method: 'GET', + path: appendQueryParam('user_ids', join(',', userIds), '/users_by_ids') + }) + .then(pipe( + JSON.parse, + map(parseUser), + reduce((acc, user) => ({ ...acc, [user.id]: user }), {}), + this.userStore.initialize + )) + .catch(err => { + this.logger.warning('error fetching initial user information:', err) + // fall back to fetching lazily + this.userStore.initialize({}) + }) } } diff --git a/src/parsers.js b/src/parsers.js new file mode 100644 index 0000000..ef1a536 --- /dev/null +++ b/src/parsers.js @@ -0,0 +1,30 @@ +import { curry, contains } from 'ramda' + +import { Room } from './room' + +export const parseRoom = curry((userStore, data) => new Room({ + createdAt: data.created_at, + createdByUserId: data.created_by_id, + deletedAt: data.deletedAt, + id: data.id, + isPrivate: data.private, + name: data.name, + updatedAt: data.updated_at, + userIds: data.member_user_ids, + userStore +})) + +export const parseUser = data => ({ + avatarURL: data.avatar_url, + createdAt: data.created_at, + customData: data.custom_data, + id: data.id, + name: data.name, + updatedAt: data.updated_at +}) + +export const parsePresenceState = data => ({ + lastSeenAt: data.last_seen_at, + state: contains(data.state, ['online', 'offline']) ? data.state : 'unknown', + userId: data.user_id +}) diff --git a/src/room.js b/src/room.js new file mode 100644 index 0000000..4e5fee6 --- /dev/null +++ b/src/room.js @@ -0,0 +1,17 @@ +import { map } from 'ramda' + +export class Room { + constructor (options) { + this.createdAt = options.createdAt + this.createdByUserId = options.createdByUserId + this.deletedAt = options.deletedAt + this.id = options.id + this.isPrivate = options.isPrivate + this.name = options.name + this.updatedAt = options.updatedAt + this.userIds = options.userIds + this.userStore = options.userStore + } + + getUsers = () => Promise.all(map(this.userStore.get, this.userIds)) +} diff --git a/src/store.js b/src/store.js new file mode 100644 index 0000000..28aa2db --- /dev/null +++ b/src/store.js @@ -0,0 +1,22 @@ +import { clone, forEachObjIndexed } from 'ramda' + +export class Store { + pending = {} + + initialize = initialStore => { + this.store = clone(initialStore) + forEachObjIndexed((resolve, key) => resolve(this.store[key])) + } + + set = (key, value) => { this.store[key] = value } + + get = key => { + if (this.store) { + return Promise.resolve(this.store[key]) + } else { + return new Promise(resolve => { + this.pending[key] = resolve + }) + } + } +} diff --git a/src/user-store.js b/src/user-store.js new file mode 100644 index 0000000..d0af5eb --- /dev/null +++ b/src/user-store.js @@ -0,0 +1,38 @@ +import { Store } from './store' +import { parseUser } from './parsers' + +export class UserStore { + constructor ({ apiInstance, presenceStore, logger }) { + this.apiInstance = apiInstance + this.presenceStore = presenceStore + this.logger = logger + } + + store = new Store() + + initialize = this.store.initialize + + set = this.store.set + + get = userId => Promise.all([ + this.store.get(userId).then(user => user || this.fetchUser(userId)), + this.presenceStore.get(userId) + ]).then(([user, presenceState]) => ({ ...user, presenceState })) + + fetchUser = userId => { + return this.apiInstance + .request({ + method: 'GET', + path: `/users/${userId}` + }) + .then(res => { + const user = parseUser(JSON.parse(res)) + this.set(userId, user) + return user + }) + .catch(err => { + this.logger.warning('error fetching user information:', err) + throw err + }) + } +} diff --git a/src/utils.js b/src/utils.js index bd9e154..edcdc8b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -18,8 +18,8 @@ export const urlEncode = pipe( // appendQueryParam :: String -> String -> String -> String export const appendQueryParam = (key, value, url) => { - const [ beforeQ, afterQ ] = split('?', url) - return beforeQ + '?' + (afterQ ? afterQ + '&' : '') + urlEncode({ [key]: value }) + const [ before, after ] = split('?', url) + return before + '?' + (after ? after + '&' : '') + urlEncode({ [key]: value }) } export const typeCheck = (name, expectedType, value) => { diff --git a/tests/main.js b/tests/main.js index 3885a9b..4e6a50f 100644 --- a/tests/main.js +++ b/tests/main.js @@ -1,4 +1,4 @@ -import test from 'tape' +import test from 'tape-catch' import { any, compose, @@ -6,7 +6,9 @@ import { curry, find, head, + length, map, + prop, once, reduce, tail, @@ -74,7 +76,7 @@ const endWithErr = curry((t, err) => t.end(`error: ${toString(err)}`)) const sendMessage = (user, room, text) => new Promise((resolve, reject) => user.sendMessage({ roomId: room.id, text }, resolve, reject)) -const sendMessages = (user, room, texts) => texts.length === 0 +const sendMessages = (user, room, texts) => length(texts) === 0 ? Promise.resolve() : sendMessage(user, room, head(texts)) .then(() => sendMessages(user, room, tail(texts))) @@ -199,17 +201,22 @@ test('[setup] create Alice', t => { }) test('connection resolves with current user object', t => { - fetchUser(t, 'alice').then(user => { - t.equal(typeof user, 'object') - t.equal(user.id, 'alice') - t.equal(user.name, 'Alice') - t.true(Array.isArray(user.rooms), 'user.rooms is an array') - t.equal(user.rooms.length, 1) - t.equal(user.rooms[0].name, `Alice's room`) - t.equal(user.rooms[0].isPrivate, false) - t.equal(user.rooms[0].createdByUserId, 'alice') - t.deepEqual(user.rooms[0].userIds, ['alice']) - t.end() + fetchUser(t, 'alice').then(alice => { + t.equal(typeof alice, 'object') + t.equal(alice.id, 'alice') + t.equal(alice.name, 'Alice') + t.true(Array.isArray(alice.rooms), 'alice.rooms is an array') + t.equal(length(alice.rooms), 1) + t.equal(alice.rooms[0].name, `Alice's room`) + t.equal(alice.rooms[0].isPrivate, false) + t.equal(alice.rooms[0].createdByUserId, 'alice') + t.deepEqual(alice.rooms[0].userIds, ['alice']) + alice.rooms[0].getUsers().then(users => { + t.true(Array.isArray(users), 'users is an array') + t.equal(length(users), 1) + t.equal(users[0].name, 'Alice') + t.end() + }).catch(endWithErr(t)) }) t.timeoutAfter(TEST_TIMEOUT) }) @@ -221,8 +228,18 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { fetchUser(t, 'alice', { addedToRoom: room => { t.equal(room.name, `Bob's room`) - t.true(any(r => r.id === room.id, alice.rooms), `should contain Bob's room`) - t.end() + t.true( + any(r => r.id === room.id, alice.rooms), + `should contain Bob's room` + ) + const br = find(r => r.id === room.id, alice.rooms) + t.true(br, `alice.rooms should contain Bob's room`) + br.getUsers() + .then(users => { + t.deepEqual(map(prop('name'), users).sort(), ['Alice', 'Bob']) + t.end() + }) + .catch(endWithErr(t)) } }) .then(a => { alice = a }) @@ -239,7 +256,7 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { // This test has to run before any tests which cause Bob to open a subscription // (since then he will already be online) -test.skip('user came online hook (user sub)', t => { +test('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') @@ -254,6 +271,8 @@ test.skip('user came online hook (user sub)', t => { // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. +// TODO cancel methods so that we can do this, and because we should have them +// anyway test.skip('typing indicators (user sub)', t => { let started diff --git a/yarn.lock b/yarn.lock index 34620ab..92b03f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1425,6 +1425,10 @@ doctrine@^2.0.0: dependencies: esutils "^2.0.2" +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + domain-browser@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2078,6 +2082,13 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2, glob@~7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + globals@^9.14.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2833,6 +2844,12 @@ mime@^1.2.11, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -3297,6 +3314,10 @@ process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + progress-stream@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" @@ -4099,6 +4120,12 @@ tap-parser@~0.4.0: inherits "~2.0.1" readable-stream "~1.1.11" +tape-catch@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tape-catch/-/tape-catch-1.0.6.tgz#12931d5ea60a03a97d9bd19d0d7d8cfc3f6cecf1" + dependencies: + global "~4.3.0" + tape-run@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/tape-run/-/tape-run-3.0.2.tgz#fbad4b77b72bab77c36e5f1c3610bfa17402c46d" From 6b37c3c6b23de169edb81a1bfe9dce326746f3f4 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 6 Feb 2018 17:46:07 +0000 Subject: [PATCH 05/99] presence updates --- src/current-user.js | 9 +++++++++ tests/main.js | 6 ++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index c8acf25..8a6f885 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -95,6 +95,15 @@ export class CurrentUser { hooks.subscriptionEstablished() } break + case 'presence_update': + const presence = parsePresenceState(body.data) + this.presenceStore.set(presence.userId, presence) + if (presence.state === 'online' && hooks.userCameOnline) { + this.userStore.get(presence.userId).then(hooks.userCameOnline) + } else if (presence.state === 'offline' && hooks.userWentOffline) { + this.userStore.get(presence.userId).then(hooks.userWentOffline) + } + break } } diff --git a/tests/main.js b/tests/main.js index 4e6a50f..2d5e301 100644 --- a/tests/main.js +++ b/tests/main.js @@ -260,12 +260,10 @@ test('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') + t.equal(user.presenceState.state, 'online') t.end() } - }) - // FIXME We have to wrap this in a timeout to give the presence - // subscription a chance to finish. Not ideal. - .then(() => setTimeout(() => fetchUser(t, 'bob'), 1000)) + }).then(() => fetchUser(t, 'bob')) t.timeoutAfter(TEST_TIMEOUT) }) From f2b926c62737321f4b335415567d6f1d5abf1f55 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Feb 2018 11:44:18 +0000 Subject: [PATCH 06/99] typing indicators, plus function style consistency --- src/chat-manager.js | 2 +- src/constants.js | 2 ++ src/current-user.js | 18 ++++++++++++++ src/token-provider.js | 20 +++++++-------- src/typing-indicators.js | 54 ++++++++++++++++++++++++++++++++++++++++ tests/main.js | 2 +- 6 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 src/constants.js create mode 100644 src/typing-indicators.js diff --git a/src/chat-manager.js b/src/chat-manager.js index f554ef5..71a7bc6 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -48,7 +48,7 @@ export class ChatManager { this.userId = userId } - connect (hooks = {}) { + connect = (hooks = {}) => { typeCheckObj('function', hooks) const currentUser = new CurrentUser({ id: this.userId, diff --git a/src/constants.js b/src/constants.js new file mode 100644 index 0000000..a9de2ea --- /dev/null +++ b/src/constants.js @@ -0,0 +1,2 @@ +export const TYPING_INDICATOR_TTL = 1500 +export const TYPING_INDICATOR_LEEWAY = 500 diff --git a/src/current-user.js b/src/current-user.js index 8a6f885..9b1f5f8 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -2,6 +2,7 @@ import { append, chain, compose, + find, join, length, map, @@ -15,6 +16,7 @@ import { appendQueryParam } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { parseUser, parseRoom, parsePresenceState } from './parsers' +import { TypingIndicators } from './typing-indicators' export class CurrentUser { constructor ({ id, apiInstance }) { @@ -27,10 +29,17 @@ export class CurrentUser { presenceStore: this.presenceStore, logger: this.logger }) + this.typingIndicators = new TypingIndicators({ + userId: this.id, + apiInstance: this.apiInstance, + logger: this.logger + }) } /* public */ + isTypingIn = roomId => this.typingIndicators.sendThrottledRequest(roomId) + /* internal */ establishUserSubscription = hooks => new Promise((resolve, reject) => this.apiInstance.subscribeNonResuming({ @@ -61,6 +70,15 @@ export class CurrentUser { hooks.addedToRoom(room) } break + case 'typing_start': // TODO 'is_typing' + const { room_id: roomId, user_id: userId } = body.data + this.userStore.get(userId) + .then(user => this.typingIndicators.onIsTyping( + find(r => r.id === roomId, this.rooms), // TODO room store + user, + hooks + )) + break } } diff --git a/src/token-provider.js b/src/token-provider.js index 2c8c97c..f3a790c 100644 --- a/src/token-provider.js +++ b/src/token-provider.js @@ -10,20 +10,18 @@ export class TokenProvider { } // TODO caching - fetchToken () { - return sendRawRequest({ - body: urlEncode({ grant_type: 'client_credentials' }), - headers: { - 'content-type': 'application/x-www-form-urlencoded' - }, - method: 'POST', - url: appendQueryParam('user_id', this.userId, this.url) - }).then(res => JSON.parse(res).access_token) - } + fetchToken = () => sendRawRequest({ + body: urlEncode({ grant_type: 'client_credentials' }), + headers: { + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + url: appendQueryParam('user_id', this.userId, this.url) + }).then(res => JSON.parse(res).access_token) // To allow ChatManager to feed the userId to the TokenProvider. Not set // directly so as not to mess with a custom TokenProvider implementation. - setUserId (userId) { + setUserId = userId => { this.userId = userId } } diff --git a/src/typing-indicators.js b/src/typing-indicators.js new file mode 100644 index 0000000..ba7652b --- /dev/null +++ b/src/typing-indicators.js @@ -0,0 +1,54 @@ +import { TYPING_INDICATOR_TTL, TYPING_INDICATOR_LEEWAY } from './constants' + +export class TypingIndicators { + constructor ({ userId, apiInstance, logger }) { + this.userId = userId + this.apiInstance = apiInstance + this.logger = logger + this.lastSentRequests = {} + this.timers = {} + } + + sendThrottledRequest = roomId => { + const now = Date.now() + const sent = this.lastSentRequests[roomId] + if (sent && now - sent < TYPING_INDICATOR_TTL - TYPING_INDICATOR_LEEWAY) { + return Promise.resolve() + } + this.lastSentRequests[roomId] = now + return this.apiInstance + .request({ + method: 'POST', + path: `/rooms/${roomId}/events`, + json: { + name: 'typing_start', // TODO 'is_typing' + user_id: this.userId + } + }) + .catch(err => { + delete this.typingRequestSent[roomId] + this.logger.warning( + `Error sending is_typing event in room ${roomId}`, + err + ) + throw err + }) + } + + onIsTyping = (room, user, hooks) => { + if (!this.timers[room.id]) { + this.timers[room.id] = {} + } + if (this.timers[room.id][user.id]) { + clearTimeout(this.timers[room.id][user.id]) + } else if (hooks.userStartedTyping) { + hooks.userStartedTyping(room, user) + } + this.timers[room.id][user.id] = setTimeout(() => { + if (hooks.userStoppedTyping) { + hooks.userStoppedTyping(room, user) + } + delete this.timers[room.id][user.id] + }, TYPING_INDICATOR_TTL) + } +} diff --git a/tests/main.js b/tests/main.js index 2d5e301..525bbdc 100644 --- a/tests/main.js +++ b/tests/main.js @@ -272,7 +272,7 @@ test('user came online hook (user sub)', t => { // TODO cancel methods so that we can do this, and because we should have them // anyway -test.skip('typing indicators (user sub)', t => { +test('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { From d3ea4272a91ab7a0ffa32006f8453904823ca061 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Feb 2018 14:40:18 +0000 Subject: [PATCH 07/99] room store --- src/current-user.js | 59 ++++++++++++++++++++++++---------------- src/parsers.js | 11 +++----- src/room-store.js | 44 ++++++++++++++++++++++++++++++ src/room.js | 20 +++++++------- src/store.js | 2 ++ src/typing-indicators.js | 2 +- src/user-store.js | 2 +- src/utils.js | 6 ++++ tests/main.js | 9 +++--- 9 files changed, 107 insertions(+), 48 deletions(-) create mode 100644 src/room-store.js diff --git a/src/current-user.js b/src/current-user.js index 9b1f5f8..e5a8c0a 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,21 +1,21 @@ import { - append, chain, compose, - find, + indexBy, join, length, map, pipe, prop, - reduce, - uniq + uniq, + values } from 'ramda' import { appendQueryParam } from './utils' import { Store } from './store' import { UserStore } from './user-store' -import { parseUser, parseRoom, parsePresenceState } from './parsers' +import { RoomStore } from './room-store' +import { parseUser, parseBasicRoom, parsePresenceState } from './parsers' import { TypingIndicators } from './typing-indicators' export class CurrentUser { @@ -29,6 +29,11 @@ export class CurrentUser { presenceStore: this.presenceStore, logger: this.logger }) + this.roomStore = new RoomStore({ + apiInstance: this.apiInstance, + userStore: this.userStore, + logger: this.logger + }) this.typingIndicators = new TypingIndicators({ userId: this.id, apiInstance: this.apiInstance, @@ -38,9 +43,14 @@ export class CurrentUser { /* public */ + get rooms () { + return values(this.roomStore.snapshot()) + } + isTypingIn = roomId => this.typingIndicators.sendThrottledRequest(roomId) /* internal */ + establishUserSubscription = hooks => new Promise((resolve, reject) => this.apiInstance.subscribeNonResuming({ path: '/users', @@ -64,20 +74,19 @@ export class CurrentUser { break case 'added_to_room': // TODO fetch new user details in bulk when added to room (etc) - const room = parseRoom(this.userStore, body.data.room) - this.rooms = append(room, this.rooms) + const basicRoom = parseBasicRoom(body.data.room) + this.roomStore.set(basicRoom.id, basicRoom) if (hooks.addedToRoom) { - hooks.addedToRoom(room) + this.roomStore.get(basicRoom.id) + .then(room => { + hooks.addedToRoom(room) + }) } break case 'typing_start': // TODO 'is_typing' const { room_id: roomId, user_id: userId } = body.data - this.userStore.get(userId) - .then(user => this.typingIndicators.onIsTyping( - find(r => r.id === roomId, this.rooms), // TODO room store - user, - hooks - )) + Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, hooks)) break } } @@ -89,7 +98,11 @@ export class CurrentUser { this.id = currentUser.id this.name = currentUser.name this.updatedAt = currentUser.updated_at - this.rooms = map(parseRoom(this.userStore), rooms) + compose( + this.roomStore.initialize, + indexBy(prop('id')), + map(parseBasicRoom) + )(rooms) } establishPresenceSubscription = hooks => new Promise((resolve, reject) => @@ -125,13 +138,11 @@ export class CurrentUser { } } - onPresenceInitialState = ({ user_states: userStates }) => { - compose( - this.presenceStore.initialize, - reduce((acc, state) => ({ ...acc, [state.userId]: state }), {}), - map(parsePresenceState) - )(userStates) - } + onPresenceInitialState = ({ user_states: userStates }) => compose( + this.presenceStore.initialize, + indexBy(prop('userId')), + map(parsePresenceState) + )(userStates) initializeUserStore = () => { const userIds = uniq(chain(prop('userIds'), this.rooms)) @@ -147,11 +158,11 @@ export class CurrentUser { .then(pipe( JSON.parse, map(parseUser), - reduce((acc, user) => ({ ...acc, [user.id]: user }), {}), + indexBy(prop('id')), this.userStore.initialize )) .catch(err => { - this.logger.warning('error fetching initial user information:', err) + this.logger.warn('error fetching initial user information:', err) // fall back to fetching lazily this.userStore.initialize({}) }) diff --git a/src/parsers.js b/src/parsers.js index ef1a536..ac97863 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -1,8 +1,6 @@ -import { curry, contains } from 'ramda' +import { contains } from 'ramda' -import { Room } from './room' - -export const parseRoom = curry((userStore, data) => new Room({ +export const parseBasicRoom = data => ({ createdAt: data.created_at, createdByUserId: data.created_by_id, deletedAt: data.deletedAt, @@ -10,9 +8,8 @@ export const parseRoom = curry((userStore, data) => new Room({ isPrivate: data.private, name: data.name, updatedAt: data.updated_at, - userIds: data.member_user_ids, - userStore -})) + userIds: data.member_user_ids +}) export const parseUser = data => ({ avatarURL: data.avatar_url, diff --git a/src/room-store.js b/src/room-store.js new file mode 100644 index 0000000..6dbcc49 --- /dev/null +++ b/src/room-store.js @@ -0,0 +1,44 @@ +import { map } from 'ramda' + +import { Store } from './store' +import { parseBasicRoom } from './parsers' +import { Room } from './room' + +export class RoomStore { + constructor ({ apiInstance, userStore, logger }) { + this.apiInstance = apiInstance + this.userStore = userStore + this.logger = logger + } + + store = new Store() + + initialize = this.store.initialize + + set = this.store.set + + get = roomId => this.store.get(roomId).then(basicRoom => + basicRoom || this.fetchBasicRoom(roomId) + ).then(this.decorate) + + fetchBasicRoom = roomId => { + return this.apiInstance + .request({ + method: 'GET', + path: `/rooms/${roomId}` + }) + .then(res => { + const basicRoom = parseBasicRoom(JSON.parse(res)) + this.set(roomId, basicRoom) + return basicRoom + }) + .catch(err => { + this.logger.warn('error fetching room information:', err) + throw err + }) + } + + decorate = basicRoom => new Room(basicRoom, this.userStore) + + snapshot = () => map(this.decorate, this.store.snapshot()) +} diff --git a/src/room.js b/src/room.js index 4e5fee6..c1dfcc0 100644 --- a/src/room.js +++ b/src/room.js @@ -1,16 +1,16 @@ import { map } from 'ramda' export class Room { - constructor (options) { - this.createdAt = options.createdAt - this.createdByUserId = options.createdByUserId - this.deletedAt = options.deletedAt - this.id = options.id - this.isPrivate = options.isPrivate - this.name = options.name - this.updatedAt = options.updatedAt - this.userIds = options.userIds - this.userStore = options.userStore + constructor (basicRoom, userStore) { + this.createdAt = basicRoom.createdAt + this.createdByUserId = basicRoom.createdByUserId + this.deletedAt = basicRoom.deletedAt + this.id = basicRoom.id + this.isPrivate = basicRoom.isPrivate + this.name = basicRoom.name + this.updatedAt = basicRoom.updatedAt + this.userIds = basicRoom.userIds + this.userStore = userStore } getUsers = () => Promise.all(map(this.userStore.get, this.userIds)) diff --git a/src/store.js b/src/store.js index 28aa2db..0c2f9ae 100644 --- a/src/store.js +++ b/src/store.js @@ -19,4 +19,6 @@ export class Store { }) } } + + snapshot = () => this.store } diff --git a/src/typing-indicators.js b/src/typing-indicators.js index ba7652b..fecaba9 100644 --- a/src/typing-indicators.js +++ b/src/typing-indicators.js @@ -27,7 +27,7 @@ export class TypingIndicators { }) .catch(err => { delete this.typingRequestSent[roomId] - this.logger.warning( + this.logger.warn( `Error sending is_typing event in room ${roomId}`, err ) diff --git a/src/user-store.js b/src/user-store.js index d0af5eb..d0e2248 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -31,7 +31,7 @@ export class UserStore { return user }) .catch(err => { - this.logger.warning('error fetching user information:', err) + this.logger.warn('error fetching user information:', err) throw err }) } diff --git a/src/utils.js b/src/utils.js index edcdc8b..c9bc37c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -36,3 +36,9 @@ export const typeCheckObj = (expectedType, obj) => forEachObjIndexed( (value, key) => typeCheck(key, expectedType, value), obj ) + +// pointfree debugging +export const trace = msg => x => { + console.log(msg, x) + return x +} diff --git a/tests/main.js b/tests/main.js index 525bbdc..43f4a56 100644 --- a/tests/main.js +++ b/tests/main.js @@ -250,6 +250,7 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { })) .then(room => { bobsRoom = room // we'll want this in the following tests + t.comment(`bob's room id:` + bobsRoom.id) }) t.timeoutAfter(TEST_TIMEOUT) }) @@ -289,11 +290,9 @@ test('typing indicators (user sub)', t => { } }), fetchUser(t, 'bob') - ]).then(([alice, bob]) => bob.isTypingIn( - bobsRoom.id, - () => {}, - err => t.end(err) - )) + ]) + .then(([alice, bob]) => bob.isTypingIn(bobsRoom.id)) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From b1b95a4096ad5205556c8a7e09451ff647f3ae73 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Feb 2018 16:58:12 +0000 Subject: [PATCH 08/99] make Store.set async --- src/current-user.js | 32 ++++++++++++++++++-------------- src/store.js | 24 +++++++++++++++++++----- src/user-store.js | 2 +- tests/main.js | 3 +-- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index e5a8c0a..ccf38ee 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -75,14 +75,18 @@ export class CurrentUser { case 'added_to_room': // TODO fetch new user details in bulk when added to room (etc) const basicRoom = parseBasicRoom(body.data.room) - this.roomStore.set(basicRoom.id, basicRoom) - if (hooks.addedToRoom) { - this.roomStore.get(basicRoom.id) - .then(room => { - hooks.addedToRoom(room) - }) - } + this.roomStore.set(basicRoom.id, basicRoom).then(room => { + if (hooks.addedToRoom) { + hooks.addedToRoom(room) + } + }) break + // case 'removed_from_room': + // const room = this.roomStore.pop(body.room_id) + // if (hooks.removedFromRoom) { + // hooks.removedFromRoom(room) + // } + // break case 'typing_start': // TODO 'is_typing' const { room_id: roomId, user_id: userId } = body.data Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) @@ -128,12 +132,13 @@ export class CurrentUser { break case 'presence_update': const presence = parsePresenceState(body.data) - this.presenceStore.set(presence.userId, presence) - if (presence.state === 'online' && hooks.userCameOnline) { - this.userStore.get(presence.userId).then(hooks.userCameOnline) - } else if (presence.state === 'offline' && hooks.userWentOffline) { - this.userStore.get(presence.userId).then(hooks.userWentOffline) - } + this.presenceStore.set(presence.userId, presence).then(p => { + if (p.state === 'online' && hooks.userCameOnline) { + this.userStore.get(p.userId).then(hooks.userCameOnline) + } else if (p.state === 'offline' && hooks.userWentOffline) { + this.userStore.get(p.userId).then(hooks.userWentOffline) + } + }) break } } @@ -163,7 +168,6 @@ export class CurrentUser { )) .catch(err => { this.logger.warn('error fetching initial user information:', err) - // fall back to fetching lazily this.userStore.initialize({}) }) } diff --git a/src/store.js b/src/store.js index 0c2f9ae..37a0d4e 100644 --- a/src/store.js +++ b/src/store.js @@ -1,21 +1,35 @@ -import { clone, forEachObjIndexed } from 'ramda' +import { clone, forEach } from 'ramda' export class Store { - pending = {} + pendingSets = [] // [{ key, value, resolve }] + pendingGets = [] // [{ key, resolve }] initialize = initialStore => { this.store = clone(initialStore) - forEachObjIndexed((resolve, key) => resolve(this.store[key])) + forEach(({ key, value, resolve }) => { + resolve(this.store[key] = value) + }, this.pendingSets) + forEach(({ key, resolve }) => { + resolve(this.store[key]) + }, this.pendingGets) } - set = (key, value) => { this.store[key] = value } + set = (key, value) => { + if (this.store) { + return Promise.resolve(this.store[key] = value) + } else { + return new Promise(resolve => { + this.pendingSets.push({ key, value, resolve }) + }) + } + } get = key => { if (this.store) { return Promise.resolve(this.store[key]) } else { return new Promise(resolve => { - this.pending[key] = resolve + this.pendingGets.push({ key, resolve }) }) } } diff --git a/src/user-store.js b/src/user-store.js index d0e2248..d278c5b 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -17,7 +17,7 @@ export class UserStore { get = userId => Promise.all([ this.store.get(userId).then(user => user || this.fetchUser(userId)), this.presenceStore.get(userId) - ]).then(([user, presenceState]) => ({ ...user, presenceState })) + ]).then(([user, presence]) => ({ ...user, presence })) fetchUser = userId => { return this.apiInstance diff --git a/tests/main.js b/tests/main.js index 43f4a56..f874d11 100644 --- a/tests/main.js +++ b/tests/main.js @@ -250,7 +250,6 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { })) .then(room => { bobsRoom = room // we'll want this in the following tests - t.comment(`bob's room id:` + bobsRoom.id) }) t.timeoutAfter(TEST_TIMEOUT) }) @@ -261,7 +260,7 @@ test('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') - t.equal(user.presenceState.state, 'online') + t.equal(user.presence.state, 'online') t.end() } }).then(() => fetchUser(t, 'bob')) From 992b27eccd3f095692832a72828efe3007e4cf07 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Feb 2018 17:40:58 +0000 Subject: [PATCH 09/99] removed from room, pop store --- package.json | 5 +++-- src/current-user.js | 13 +++++++------ src/room-store.js | 6 +++++- src/store.js | 5 +++++ tests/main.js | 16 +++++++--------- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 91953e3..c47722b 100644 --- a/package.json +++ b/package.json @@ -45,9 +45,10 @@ "build": "yarn build:all", "build:all": "yarn build:web", "build:web": "rollup -c rollup/web.js", - "test": "browserify tests/main.js -t babelify | tape-run | faucet", + "test": "browserify tests/main.js -t babelify | tape-run", "lint:build": "clear && yarn lint && clear && yarn build", - "lint:build:test": "yarn lint:build && clear && yarn test" + "lint:build:test": "yarn lint:build && clear && yarn test | faucet", + "lint:build:test:raw": "yarn lint:build && clear && yarn test" }, "babel": { "presets": [ diff --git a/src/current-user.js b/src/current-user.js index ccf38ee..1c81f0e 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -81,12 +81,13 @@ export class CurrentUser { } }) break - // case 'removed_from_room': - // const room = this.roomStore.pop(body.room_id) - // if (hooks.removedFromRoom) { - // hooks.removedFromRoom(room) - // } - // break + case 'removed_from_room': + this.roomStore.pop(body.data.room_id).then(room => { + if (hooks.removedFromRoom) { + hooks.removedFromRoom(room) + } + }) + break case 'typing_start': // TODO 'is_typing' const { room_id: roomId, user_id: userId } = body.data Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) diff --git a/src/room-store.js b/src/room-store.js index 6dbcc49..6704b6c 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -21,6 +21,8 @@ export class RoomStore { basicRoom || this.fetchBasicRoom(roomId) ).then(this.decorate) + pop = roomId => this.store.pop(roomId).then(this.decorate) + fetchBasicRoom = roomId => { return this.apiInstance .request({ @@ -38,7 +40,9 @@ export class RoomStore { }) } - decorate = basicRoom => new Room(basicRoom, this.userStore) + decorate = basicRoom => basicRoom + ? new Room(basicRoom, this.userStore) + : undefined snapshot = () => map(this.decorate, this.store.snapshot()) } diff --git a/src/store.js b/src/store.js index 37a0d4e..39a7268 100644 --- a/src/store.js +++ b/src/store.js @@ -34,5 +34,10 @@ export class Store { } } + pop = key => this.get(key).then(value => { + delete this.store[key] + return value + }) + snapshot = () => this.store } diff --git a/tests/main.js b/tests/main.js index f874d11..fb61a7c 100644 --- a/tests/main.js +++ b/tests/main.js @@ -343,20 +343,18 @@ test.skip('room updated hook', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`removed from room hook [removes Alice from Bob's room]`, t => { +test(`removed from room hook [removes Alice from Bob's room]`, t => { fetchUser(t, 'alice', { removedFromRoom: room => { t.equal(room.id, bobsRoom.id) t.end() } - }) - .then(() => server.apiRequest({ - method: 'PUT', - path: `/rooms/${bobsRoom.id}/users/remove`, - body: { user_ids: ['alice'] }, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) - .catch(endWithErr(t)) + }).then(() => server.apiRequest({ + method: 'PUT', + path: `/rooms/${bobsRoom.id}/users/remove`, + body: { user_ids: ['alice'] }, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) t.timeoutAfter(TEST_TIMEOUT) }) From b41a60fb718d589fd2bbcb8b270952fbd913e8b9 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Feb 2018 18:29:00 +0000 Subject: [PATCH 10/99] get users (wip) --- src/current-user.js | 4 ++++ src/room.js | 7 +++++++ src/user-store.js | 10 ++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/current-user.js b/src/current-user.js index 1c81f0e..8f2c2b9 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -47,6 +47,10 @@ export class CurrentUser { return values(this.roomStore.snapshot()) } + get users () { + return values(this.userStore.snapshot()) + } + isTypingIn = roomId => this.typingIndicators.sendThrottledRequest(roomId) /* internal */ diff --git a/src/room.js b/src/room.js index c1dfcc0..bcc2def 100644 --- a/src/room.js +++ b/src/room.js @@ -14,4 +14,11 @@ export class Room { } getUsers = () => Promise.all(map(this.userStore.get, this.userIds)) + + get users () { + return filter( + user => contains(user.id, this.userIds), + values(this.userStore.snapshot()) + ) + } } diff --git a/src/user-store.js b/src/user-store.js index d278c5b..9b08b25 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -1,3 +1,5 @@ +import { map } from 'ramda' + import { Store } from './store' import { parseUser } from './parsers' @@ -35,4 +37,12 @@ export class UserStore { throw err }) } + + snapshot = () => { + const presenceSnapshot = this.presenceStore.snapshot() + return map( + user => ({ ...user, presence: presenceSnapshot[user.id] }), + this.store.snapshot() + ) + } } From b1790de89c1ff61ca6c67111c1387af2d088973e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 11:14:59 +0000 Subject: [PATCH 11/99] pull user subscription out in to own class --- src/current-user.js | 68 ++++++------------------------------- src/room-store.js | 4 +++ src/room.js | 2 +- src/user-subscription.js | 72 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 58 deletions(-) create mode 100644 src/user-subscription.js diff --git a/src/current-user.js b/src/current-user.js index 8f2c2b9..6f97181 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -15,8 +15,9 @@ import { appendQueryParam } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseUser, parseBasicRoom, parsePresenceState } from './parsers' +import { parseUser, parsePresenceState } from './parsers' import { TypingIndicators } from './typing-indicators' +import { UserSubscription } from './user-subscription' export class CurrentUser { constructor ({ id, apiInstance }) { @@ -55,63 +56,16 @@ export class CurrentUser { /* internal */ - establishUserSubscription = hooks => new Promise((resolve, reject) => - this.apiInstance.subscribeNonResuming({ - path: '/users', - listeners: { - onError: reject, - onEvent: this.onUserEvent({ - ...hooks, - subscriptionEstablished: resolve - }) - } + establishUserSubscription = hooks => { + this.userSubscription = new UserSubscription({ hooks, ...this }) + return this.userSubscription.connect().then(({ user, basicRooms }) => { + this.avatarURL = user.avatarURL + this.createdAt = user.createdAt + this.customData = user.customData + this.name = user.name + this.updatedAt = user.updatedAt + this.roomStore.initialize(indexBy(prop('id'), basicRooms)) }) - ) - - onUserEvent = hooks => ({ body }) => { - switch (body.event_name) { - case 'initial_state': - this.onUserInitialState(body.data) - if (hooks.subscriptionEstablished) { - hooks.subscriptionEstablished() - } - break - case 'added_to_room': - // TODO fetch new user details in bulk when added to room (etc) - const basicRoom = parseBasicRoom(body.data.room) - this.roomStore.set(basicRoom.id, basicRoom).then(room => { - if (hooks.addedToRoom) { - hooks.addedToRoom(room) - } - }) - break - case 'removed_from_room': - this.roomStore.pop(body.data.room_id).then(room => { - if (hooks.removedFromRoom) { - hooks.removedFromRoom(room) - } - }) - break - case 'typing_start': // TODO 'is_typing' - const { room_id: roomId, user_id: userId } = body.data - Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, hooks)) - break - } - } - - onUserInitialState = ({ current_user: currentUser, rooms }) => { - this.avatarURL = currentUser.avatar_url - this.createdAt = currentUser.created_at - this.customData = currentUser.custom_data - this.id = currentUser.id - this.name = currentUser.name - this.updatedAt = currentUser.updated_at - compose( - this.roomStore.initialize, - indexBy(prop('id')), - map(parseBasicRoom) - )(rooms) } establishPresenceSubscription = hooks => new Promise((resolve, reject) => diff --git a/src/room-store.js b/src/room-store.js index 6704b6c..6ee590b 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -23,6 +23,10 @@ export class RoomStore { pop = roomId => this.store.pop(roomId).then(this.decorate) + removeUserFromRoom = (roomId, userId) => this.store.pop(roomId).then(r => + this.set(roomId, { ...r, userIds: r.userIds.filter(id => id !== userId) }) + ) + fetchBasicRoom = roomId => { return this.apiInstance .request({ diff --git a/src/room.js b/src/room.js index bcc2def..f35294c 100644 --- a/src/room.js +++ b/src/room.js @@ -1,4 +1,4 @@ -import { map } from 'ramda' +import { contains, filter, map, values } from 'ramda' export class Room { constructor (basicRoom, userStore) { diff --git a/src/user-subscription.js b/src/user-subscription.js new file mode 100644 index 0000000..1ec8f3f --- /dev/null +++ b/src/user-subscription.js @@ -0,0 +1,72 @@ +import { map } from 'ramda' + +import { parseBasicRoom, parseUser } from './parsers' + +export class UserSubscription { + constructor ({ hooks, apiInstance, userStore, roomStore, typingIndicators }) { + this.hooks = hooks + this.apiInstance = apiInstance + this.userStore = userStore + this.roomStore = roomStore + this.typingIndicators = typingIndicators + } + + connect = () => new Promise((resolve, reject) => { + this.hooks.subscriptionEstablished = resolve + this.apiInstance.subscribeNonResuming({ + path: '/users', + listeners: { + onError: reject, + onEvent: this.onEvent + } + }) + }) + + onEvent = ({ body }) => { + switch (body.event_name) { + case 'initial_state': + this.onInitialState(body.data) + break + case 'added_to_room': + // TODO fetch new user details in bulk when added to room (etc) + const basicRoom = parseBasicRoom(body.data.room) + this.roomStore.set(basicRoom.id, basicRoom).then(room => { + if (this.hooks.addedToRoom) { + this.hooks.addedToRoom(room) + } + }) + break + case 'removed_from_room': + this.roomStore.pop(body.data.room_id).then(room => { + if (this.hooks.removedFromRoom) { + this.hooks.removedFromRoom(room) + } + }) + break + case 'user_joined': + console.log('user_joined', body.data) + break + case 'user_left': + console.log('user_left', body.data) + // const { room_id: roomId, user_id: userId } = body.data + // this.roomStore.removeUserFromRoom(roomId, userId) + // if (this.hooks.userLeftRoom) { + // Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + // .then(([r, u]) => this.hooks.userLeftRoom(r, u)) + // } + break + case 'typing_start': // TODO 'is_typing' + const { room_id: roomId, user_id: userId } = body.data + Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) + break + } + } + + onInitialState = ({ current_user: userData, rooms: roomsData }) => { + this.hooks.subscriptionEstablished({ + user: parseUser(userData), + basicRooms: map(parseBasicRoom, roomsData) + }) + } +} From c9b144737bb79cf57e795e6cf690467828b66ff6 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 13:42:05 +0000 Subject: [PATCH 12/99] split presence subscription out in to own class --- package.json | 7 ++-- src/chat-manager.js | 3 +- src/current-user.js | 66 ++++++++++++------------------------ src/presence-subscription.js | 51 ++++++++++++++++++++++++++++ src/room-store.js | 6 ++-- src/typing-indicators.js | 6 ++-- src/user-store.js | 6 ++-- src/user-subscription.js | 35 +++++++++---------- 8 files changed, 105 insertions(+), 75 deletions(-) create mode 100644 src/presence-subscription.js diff --git a/package.json b/package.json index c47722b..2266c55 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,11 @@ "build": "yarn build:all", "build:all": "yarn build:web", "build:web": "rollup -c rollup/web.js", - "test": "browserify tests/main.js -t babelify | tape-run", + "test": "yarn test:raw | faucet", + "test:raw": "browserify tests/main.js -t babelify | tape-run", "lint:build": "clear && yarn lint && clear && yarn build", - "lint:build:test": "yarn lint:build && clear && yarn test | faucet", - "lint:build:test:raw": "yarn lint:build && clear && yarn test" + "lint:build:test": "yarn lint:build && clear && yarn test", + "lint:build:test:raw": "yarn lint:build && clear && yarn test:raw" }, "babel": { "presets": [ diff --git a/src/chat-manager.js b/src/chat-manager.js index 71a7bc6..b411ca6 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -55,8 +55,7 @@ export class ChatManager { apiInstance: this.apiInstance }) return Promise.all([ - currentUser.establishUserSubscription(hooks) - .then(currentUser.initializeUserStore), + currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) // currentUser.initializeCursorStore() ]).then(() => currentUser) diff --git a/src/current-user.js b/src/current-user.js index 6f97181..13c85a2 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,6 +1,5 @@ import { chain, - compose, indexBy, join, length, @@ -15,9 +14,10 @@ import { appendQueryParam } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseUser, parsePresenceState } from './parsers' +import { parseUser } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' +import { PresenceSubscription } from './presence-subscription' export class CurrentUser { constructor ({ id, apiInstance }) { @@ -26,18 +26,18 @@ export class CurrentUser { this.logger = apiInstance.logger this.presenceStore = new Store() this.userStore = new UserStore({ - apiInstance, + instance: this.apiInstance, presenceStore: this.presenceStore, logger: this.logger }) this.roomStore = new RoomStore({ - apiInstance: this.apiInstance, + instance: this.apiInstance, userStore: this.userStore, logger: this.logger }) this.typingIndicators = new TypingIndicators({ userId: this.id, - apiInstance: this.apiInstance, + instance: this.apiInstance, logger: this.logger }) } @@ -57,7 +57,14 @@ export class CurrentUser { /* internal */ establishUserSubscription = hooks => { - this.userSubscription = new UserSubscription({ hooks, ...this }) + this.userSubscription = new UserSubscription({ + hooks, + userId: this.id, + instance: this.apiInstance, + userStore: this.userStore, + roomStore: this.roomStore, + typingIndicators: this.typingIndicators + }) return this.userSubscription.connect().then(({ user, basicRooms }) => { this.avatarURL = user.avatarURL this.createdAt = user.createdAt @@ -65,49 +72,20 @@ export class CurrentUser { this.name = user.name this.updatedAt = user.updatedAt this.roomStore.initialize(indexBy(prop('id'), basicRooms)) - }) + }).then(this.initializeUserStore) } - establishPresenceSubscription = hooks => new Promise((resolve, reject) => - this.apiInstance.subscribeNonResuming({ - path: `/users/${this.id}/presence`, - listeners: { - onError: reject, - onEvent: this.onPresenceEvent({ - ...hooks, - subscriptionEstablished: resolve - }) - } + establishPresenceSubscription = hooks => { + this.presenceSubscription = new PresenceSubscription({ + hooks, + userId: this.id, + instance: this.apiInstance, + userStore: this.userStore, + presenceStore: this.presenceStore }) - ) - - onPresenceEvent = hooks => ({ body }) => { - switch (body.event_name) { - case 'initial_state': - this.onPresenceInitialState(body.data) - if (hooks.subscriptionEstablished) { - hooks.subscriptionEstablished() - } - break - case 'presence_update': - const presence = parsePresenceState(body.data) - this.presenceStore.set(presence.userId, presence).then(p => { - if (p.state === 'online' && hooks.userCameOnline) { - this.userStore.get(p.userId).then(hooks.userCameOnline) - } else if (p.state === 'offline' && hooks.userWentOffline) { - this.userStore.get(p.userId).then(hooks.userWentOffline) - } - }) - break - } + return this.presenceSubscription.connect() } - onPresenceInitialState = ({ user_states: userStates }) => compose( - this.presenceStore.initialize, - indexBy(prop('userId')), - map(parsePresenceState) - )(userStates) - initializeUserStore = () => { const userIds = uniq(chain(prop('userIds'), this.rooms)) if (length(userIds) === 0) { diff --git a/src/presence-subscription.js b/src/presence-subscription.js new file mode 100644 index 0000000..57a32b9 --- /dev/null +++ b/src/presence-subscription.js @@ -0,0 +1,51 @@ +import { indexBy, prop, map } from 'ramda' + +import { parsePresenceState } from './parsers' + +export class PresenceSubscription { + constructor (options) { + this.userId = options.userId + this.hooks = options.hooks + this.instance = options.instance + this.userStore = options.userStore + this.presenceStore = options.presenceStore + } + + connect () { + return new Promise((resolve, reject) => { + this.hooks = { ...this.hooks, subscriptionEstablished: resolve } + this.instance.subscribeNonResuming({ + path: `/users/${this.userId}/presence`, + listeners: { + onError: reject, + onEvent: this.onEvent + } + }) + }) + } + + onEvent = ({ body }) => { + switch (body.event_name) { + case 'initial_state': + this.onInitialState(body.data) + break + case 'presence_update': + const presence = parsePresenceState(body.data) + this.presenceStore.set(presence.userId, presence).then(p => { + if (p.state === 'online' && this.hooks.userCameOnline) { + this.userStore.get(p.userId).then(this.hooks.userCameOnline) + } else if (p.state === 'offline' && this.hooks.userWentOffline) { + this.userStore.get(p.userId).then(this.hooks.userWentOffline) + } + }) + break + } + } + + onInitialState = ({ user_states: userStates }) => { + this.presenceStore.initialize( + indexBy(prop('userId'), map(parsePresenceState, userStates)) + ) + this.hooks.subscriptionEstablished() + } +} diff --git a/src/room-store.js b/src/room-store.js index 6ee590b..7cf018f 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -5,8 +5,8 @@ import { parseBasicRoom } from './parsers' import { Room } from './room' export class RoomStore { - constructor ({ apiInstance, userStore, logger }) { - this.apiInstance = apiInstance + constructor ({ instance, userStore, logger }) { + this.instance = instance this.userStore = userStore this.logger = logger } @@ -28,7 +28,7 @@ export class RoomStore { ) fetchBasicRoom = roomId => { - return this.apiInstance + return this.instance .request({ method: 'GET', path: `/rooms/${roomId}` diff --git a/src/typing-indicators.js b/src/typing-indicators.js index fecaba9..52d90d6 100644 --- a/src/typing-indicators.js +++ b/src/typing-indicators.js @@ -1,9 +1,9 @@ import { TYPING_INDICATOR_TTL, TYPING_INDICATOR_LEEWAY } from './constants' export class TypingIndicators { - constructor ({ userId, apiInstance, logger }) { + constructor ({ userId, instance, logger }) { this.userId = userId - this.apiInstance = apiInstance + this.instance = instance this.logger = logger this.lastSentRequests = {} this.timers = {} @@ -16,7 +16,7 @@ export class TypingIndicators { return Promise.resolve() } this.lastSentRequests[roomId] = now - return this.apiInstance + return this.instance .request({ method: 'POST', path: `/rooms/${roomId}/events`, diff --git a/src/user-store.js b/src/user-store.js index 9b08b25..ff3a49a 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -4,8 +4,8 @@ import { Store } from './store' import { parseUser } from './parsers' export class UserStore { - constructor ({ apiInstance, presenceStore, logger }) { - this.apiInstance = apiInstance + constructor ({ instance, presenceStore, logger }) { + this.instance = instance this.presenceStore = presenceStore this.logger = logger } @@ -22,7 +22,7 @@ export class UserStore { ]).then(([user, presence]) => ({ ...user, presence })) fetchUser = userId => { - return this.apiInstance + return this.instance .request({ method: 'GET', path: `/users/${userId}` diff --git a/src/user-subscription.js b/src/user-subscription.js index 1ec8f3f..30d7fcc 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -3,24 +3,27 @@ import { map } from 'ramda' import { parseBasicRoom, parseUser } from './parsers' export class UserSubscription { - constructor ({ hooks, apiInstance, userStore, roomStore, typingIndicators }) { - this.hooks = hooks - this.apiInstance = apiInstance - this.userStore = userStore - this.roomStore = roomStore - this.typingIndicators = typingIndicators + constructor (options) { + this.userId = options.userId + this.hooks = options.hooks + this.instance = options.instance + this.userStore = options.userStore + this.roomStore = options.roomStore + this.typingIndicators = options.typingIndicators } - connect = () => new Promise((resolve, reject) => { - this.hooks.subscriptionEstablished = resolve - this.apiInstance.subscribeNonResuming({ - path: '/users', - listeners: { - onError: reject, - onEvent: this.onEvent - } + connect () { + return new Promise((resolve, reject) => { + this.hooks = { ...this.hooks, subscriptionEstablished: resolve } + this.instance.subscribeNonResuming({ + path: '/users', + listeners: { + onError: reject, + onEvent: this.onEvent + } + }) }) - }) + } onEvent = ({ body }) => { switch (body.event_name) { @@ -44,10 +47,8 @@ export class UserSubscription { }) break case 'user_joined': - console.log('user_joined', body.data) break case 'user_left': - console.log('user_left', body.data) // const { room_id: roomId, user_id: userId } = body.data // this.roomStore.removeUserFromRoom(roomId, userId) // if (this.hooks.userLeftRoom) { From 3f56054457845054b316d08bc245e06853064443 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 13:45:40 +0000 Subject: [PATCH 13/99] simplify presence sub onEvent --- src/presence-subscription.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/presence-subscription.js b/src/presence-subscription.js index 57a32b9..ed100b7 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -30,14 +30,7 @@ export class PresenceSubscription { this.onInitialState(body.data) break case 'presence_update': - const presence = parsePresenceState(body.data) - this.presenceStore.set(presence.userId, presence).then(p => { - if (p.state === 'online' && this.hooks.userCameOnline) { - this.userStore.get(p.userId).then(this.hooks.userCameOnline) - } else if (p.state === 'offline' && this.hooks.userWentOffline) { - this.userStore.get(p.userId).then(this.hooks.userWentOffline) - } - }) + this.onPresenceUpdate(body.data) break } } @@ -48,4 +41,15 @@ export class PresenceSubscription { ) this.hooks.subscriptionEstablished() } + + onPresenceUpdate = data => { + const presence = parsePresenceState(data) + this.presenceStore.set(presence.userId, presence).then(p => { + if (p.state === 'online' && this.hooks.userCameOnline) { + this.userStore.get(p.userId).then(this.hooks.userCameOnline) + } else if (p.state === 'offline' && this.hooks.userWentOffline) { + this.userStore.get(p.userId).then(this.hooks.userWentOffline) + } + }) + } } From 2c05ffe3030d87eb59ca39ca3d14a011c0def3c5 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 13:55:01 +0000 Subject: [PATCH 14/99] clean up userSubscription onEvent --- src/user-subscription.js | 45 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/user-subscription.js b/src/user-subscription.js index 30d7fcc..38e0910 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -31,23 +31,13 @@ export class UserSubscription { this.onInitialState(body.data) break case 'added_to_room': - // TODO fetch new user details in bulk when added to room (etc) - const basicRoom = parseBasicRoom(body.data.room) - this.roomStore.set(basicRoom.id, basicRoom).then(room => { - if (this.hooks.addedToRoom) { - this.hooks.addedToRoom(room) - } - }) + this.onAddedToRoom(body.data) break case 'removed_from_room': - this.roomStore.pop(body.data.room_id).then(room => { - if (this.hooks.removedFromRoom) { - this.hooks.removedFromRoom(room) - } - }) - break - case 'user_joined': + this.onRemovedFromRoom(body.data) break + // case 'user_joined': + // break case 'user_left': // const { room_id: roomId, user_id: userId } = body.data // this.roomStore.removeUserFromRoom(roomId, userId) @@ -57,9 +47,7 @@ export class UserSubscription { // } break case 'typing_start': // TODO 'is_typing' - const { room_id: roomId, user_id: userId } = body.data - Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) + this.onTypingStart(body.data) break } } @@ -70,4 +58,27 @@ export class UserSubscription { basicRooms: map(parseBasicRoom, roomsData) }) } + + onAddedToRoom = ({ room: roomData }) => { + // TODO fetch new user details in bulk when added to room (etc) + const basicRoom = parseBasicRoom(roomData) + this.roomStore.set(basicRoom.id, basicRoom).then(room => { + if (this.hooks.addedToRoom) { + this.hooks.addedToRoom(room) + } + }) + } + + onRemovedFromRoom = ({ room_id: roomId }) => { + this.roomStore.pop(roomId).then(room => { + if (this.hooks.removedFromRoom) { + this.hooks.removedFromRoom(room) + } + }) + } + + onTypingStart = ({ room_id: roomId, user_id: userId }) => { + Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) + } } From 3726718f4bd0fe72741952299072315856e2df99 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 13:58:13 +0000 Subject: [PATCH 15/99] user left hook --- src/user-subscription.js | 15 +++++++++------ tests/main.js | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/user-subscription.js b/src/user-subscription.js index 38e0910..d64232f 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -39,12 +39,7 @@ export class UserSubscription { // case 'user_joined': // break case 'user_left': - // const { room_id: roomId, user_id: userId } = body.data - // this.roomStore.removeUserFromRoom(roomId, userId) - // if (this.hooks.userLeftRoom) { - // Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - // .then(([r, u]) => this.hooks.userLeftRoom(r, u)) - // } + this.onUserLeft(body.data) break case 'typing_start': // TODO 'is_typing' this.onTypingStart(body.data) @@ -77,6 +72,14 @@ export class UserSubscription { }) } + onUserLeft = ({ room_id: roomId, user_id: userId }) => { + this.roomStore.removeUserFromRoom(roomId, userId) + if (this.hooks.userLeftRoom) { + Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + .then(([r, u]) => this.hooks.userLeftRoom(r, u)) + } + } + onTypingStart = ({ room_id: roomId, user_id: userId }) => { Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) diff --git a/tests/main.js b/tests/main.js index fb61a7c..ab6e6e7 100644 --- a/tests/main.js +++ b/tests/main.js @@ -295,7 +295,7 @@ test('typing indicators (user sub)', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('user left room hook (user sub) [removes Bob from his own room]', t => { +test('user left room hook (user sub) [removes Bob from his own room]', t => { fetchUser(t, 'alice', { userLeftRoom: (room, user) => { t.equal(room.id, bobsRoom.id) From 01ce32985765f828e204cfd94480f4e2727780ac Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 14:12:10 +0000 Subject: [PATCH 16/99] onUserJoined --- src/room-store.js | 8 ++++++-- src/user-subscription.js | 27 +++++++++++++++++++++------ tests/main.js | 2 +- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/room-store.js b/src/room-store.js index 7cf018f..91f192f 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -1,4 +1,4 @@ -import { map } from 'ramda' +import { append, map, filter, uniq } from 'ramda' import { Store } from './store' import { parseBasicRoom } from './parsers' @@ -23,8 +23,12 @@ export class RoomStore { pop = roomId => this.store.pop(roomId).then(this.decorate) + addUserToRoom = (roomId, userId) => this.store.pop(roomId).then(r => + this.set(roomId, { ...r, userIds: uniq(append(userId, r.userIds)) }) + ) + removeUserFromRoom = (roomId, userId) => this.store.pop(roomId).then(r => - this.set(roomId, { ...r, userIds: r.userIds.filter(id => id !== userId) }) + this.set(roomId, { ...r, userIds: filter(id => id !== userId, r.userIds) }) ) fetchBasicRoom = roomId => { diff --git a/src/user-subscription.js b/src/user-subscription.js index d64232f..2afae57 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -36,8 +36,9 @@ export class UserSubscription { case 'removed_from_room': this.onRemovedFromRoom(body.data) break - // case 'user_joined': - // break + case 'user_joined': + this.onUserJoined(body.data) + break case 'user_left': this.onUserLeft(body.data) break @@ -72,12 +73,26 @@ export class UserSubscription { }) } + onUserJoined = ({ room_id: roomId, user_id: userId }) => { + this.roomStore.addUserToRoom(roomId, userId).then(() => { + Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) + .then(([r, u]) => { + if (this.hooks.userJoinedRoom) { + this.hooks.userJoinedRoom(r, u) + } + }) + }) + } + onUserLeft = ({ room_id: roomId, user_id: userId }) => { - this.roomStore.removeUserFromRoom(roomId, userId) - if (this.hooks.userLeftRoom) { + this.roomStore.removeUserFromRoom(roomId, userId).then(() => { Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => this.hooks.userLeftRoom(r, u)) - } + .then(([r, u]) => { + if (this.hooks.userLeftRoom) { + this.hooks.userLeftRoom(r, u) + } + }) + }) } onTypingStart = ({ room_id: roomId, user_id: userId }) => { diff --git a/tests/main.js b/tests/main.js index ab6e6e7..6c5a852 100644 --- a/tests/main.js +++ b/tests/main.js @@ -311,7 +311,7 @@ test('user left room hook (user sub) [removes Bob from his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('user joined room hook (user sub) [Bob rejoins his own room]', t => { +test('user joined room hook (user sub) [Bob rejoins his own room]', t => { fetchUser(t, 'alice', { userJoinedRoom: (room, user) => { t.equal(room.id, bobsRoom.id) From fcdf1f8bcfe3e3df9e1cbfd21056e520e1ff4c6f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 14:31:02 +0000 Subject: [PATCH 17/99] room updated hook --- src/room-store.js | 8 ++++++-- src/user-subscription.js | 14 +++++++++++++- tests/main.js | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/room-store.js b/src/room-store.js index 91f192f..72e2efc 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -1,4 +1,4 @@ -import { append, map, filter, uniq } from 'ramda' +import { append, map, mergeWith, filter, uniq } from 'ramda' import { Store } from './store' import { parseBasicRoom } from './parsers' @@ -15,7 +15,7 @@ export class RoomStore { initialize = this.store.initialize - set = this.store.set + set = (key, value) => this.store.set(key, value).then(this.decorate) get = roomId => this.store.get(roomId).then(basicRoom => basicRoom || this.fetchBasicRoom(roomId) @@ -31,6 +31,10 @@ export class RoomStore { this.set(roomId, { ...r, userIds: filter(id => id !== userId, r.userIds) }) ) + update = (roomId, updates) => this.store.pop(roomId).then(r => + this.set(roomId, mergeWith((x, y) => y || x, r, updates)) + ) + fetchBasicRoom = roomId => { return this.instance .request({ diff --git a/src/user-subscription.js b/src/user-subscription.js index 2afae57..064c9dc 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -42,6 +42,9 @@ export class UserSubscription { case 'user_left': this.onUserLeft(body.data) break + case 'room_updated': + this.onRoomUpdated(body.data) + break case 'typing_start': // TODO 'is_typing' this.onTypingStart(body.data) break @@ -56,7 +59,7 @@ export class UserSubscription { } onAddedToRoom = ({ room: roomData }) => { - // TODO fetch new user details in bulk when added to room (etc) + // TODO fetch new user details in bulk when added to room const basicRoom = parseBasicRoom(roomData) this.roomStore.set(basicRoom.id, basicRoom).then(room => { if (this.hooks.addedToRoom) { @@ -95,6 +98,15 @@ export class UserSubscription { }) } + onRoomUpdated = ({ room: roomData }) => { + const updates = parseBasicRoom(roomData) + this.roomStore.update(updates.id, updates).then(room => { + if (this.hooks.roomUpdated) { + this.hooks.roomUpdated(room) + } + }) + } + onTypingStart = ({ room_id: roomId, user_id: userId }) => { Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) diff --git a/tests/main.js b/tests/main.js index 6c5a852..053edd1 100644 --- a/tests/main.js +++ b/tests/main.js @@ -327,7 +327,7 @@ test('user joined room hook (user sub) [Bob rejoins his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('room updated hook', t => { +test('room updated hook', t => { fetchUser(t, 'alice', { roomUpdated: room => { t.equal(room.id, bobsRoom.id) From 26837940f0985c8e8cd3d7b9a9bf67d0a9504097 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 14:35:41 +0000 Subject: [PATCH 18/99] room deleted hook --- src/user-subscription.js | 11 +++++++++++ tests/main.js | 14 ++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/user-subscription.js b/src/user-subscription.js index 064c9dc..6d7c4a6 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -45,6 +45,9 @@ export class UserSubscription { case 'room_updated': this.onRoomUpdated(body.data) break + case 'room_deleted': + this.onRoomDeleted(body.data) + break case 'typing_start': // TODO 'is_typing' this.onTypingStart(body.data) break @@ -107,6 +110,14 @@ export class UserSubscription { }) } + onRoomDeleted = ({ room_id: roomId }) => { + this.roomStore.pop(roomId).then(room => { + if (room && this.hooks.roomDeleted) { + this.hooks.roomDeleted(room) + } + }) + } + onTypingStart = ({ room_id: roomId, user_id: userId }) => { Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) diff --git a/tests/main.js b/tests/main.js index 053edd1..32f4d20 100644 --- a/tests/main.js +++ b/tests/main.js @@ -358,19 +358,17 @@ test(`removed from room hook [removes Alice from Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`room deleted hook [destroys Alice's room]`, t => { +test(`room deleted hook [destroys Alice's room]`, t => { fetchUser(t, 'alice', { roomDeleted: room => { t.equal(room.id, alicesRoom.id) t.end() } - }) - .then(() => server.apiRequest({ - method: 'DELETE', - path: `/rooms/${alicesRoom.id}`, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) - .catch(endWithErr(t)) + }).then(() => server.apiRequest({ + method: 'DELETE', + path: `/rooms/${alicesRoom.id}`, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) t.timeoutAfter(TEST_TIMEOUT) }) From 16bd3fc8c7e4aa7a2ed6c9ce8f5363310af0fa19 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 15:19:36 +0000 Subject: [PATCH 19/99] create room --- src/chat-manager.js | 2 +- src/current-user.js | 37 ++++++++++++++++++++++++++++++++++--- src/utils.js | 16 ++++++++++++---- tests/main.js | 45 ++++++++++++++++++++++++--------------------- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/chat-manager.js b/src/chat-manager.js index b411ca6..b712b3e 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -49,7 +49,7 @@ export class ChatManager { } connect = (hooks = {}) => { - typeCheckObj('function', hooks) + typeCheckObj('hooks', 'function', hooks) const currentUser = new CurrentUser({ id: this.userId, apiInstance: this.apiInstance diff --git a/src/current-user.js b/src/current-user.js index 13c85a2..d8ca914 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -10,11 +10,11 @@ import { values } from 'ramda' -import { appendQueryParam } from './utils' +import { appendQueryParam, typeCheck, typeCheckArr } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseUser } from './parsers' +import { parseUser, parseBasicRoom } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' @@ -52,7 +52,38 @@ export class CurrentUser { return values(this.userStore.snapshot()) } - isTypingIn = roomId => this.typingIndicators.sendThrottledRequest(roomId) + isTypingIn (roomId) { + typeCheck('roomId', 'number', roomId) + return this.typingIndicators.sendThrottledRequest(roomId) + } + + createRoom (options = {}) { + typeCheck('options', 'object', options) + if (options.name !== undefined) { + typeCheck('name', 'string', options.name) + } + if (options.addUserIds !== undefined) { + typeCheckArr('addUserIds', 'string', options.addUserIds) + } + return this.apiInstance.request({ + method: 'POST', + path: '/rooms', + json: { + created_by_id: this.id, + name: options.name, + private: !!options.private, + user_ids: options.addUserIds + } + }) + .then(res => { + const basicRoom = parseBasicRoom(JSON.parse(res)) + return this.roomStore.set(basicRoom.id, basicRoom) + }) + .catch(err => { + this.logger.warning('error creating room:', err) + throw err + }) + } /* internal */ diff --git a/src/utils.js b/src/utils.js index c9bc37c..a36c3e9 100644 --- a/src/utils.js +++ b/src/utils.js @@ -31,11 +31,19 @@ export const typeCheck = (name, expectedType, value) => { } } +// checks that all of an arrays elements are of the given type +export const typeCheckArr = (name, expectedType, arr) => { + if (!Array.isArray(arr)) { + throw new TypeError(`expected ${name} to be an array`) + } + arr.forEach((value, i) => typeCheck(`${name}[${i}]`, expectedType, value)) +} + // checks that all of an objects values are of the given type -export const typeCheckObj = (expectedType, obj) => forEachObjIndexed( - (value, key) => typeCheck(key, expectedType, value), - obj -) +export const typeCheckObj = (name, expectedType, obj) => { + typeCheck(name, 'object', obj) + forEachObjIndexed((value, key) => typeCheck(key, expectedType, value), obj) +} // pointfree debugging export const trace = msg => x => { diff --git a/tests/main.js b/tests/main.js index 32f4d20..5dd6cff 100644 --- a/tests/main.js +++ b/tests/main.js @@ -372,51 +372,54 @@ test(`room deleted hook [destroys Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create room [creates Alice's new room]`, t => { - fetchUser(t, 'alice').then(alice => alice.createRoom( - { name: `Alice's new room` }, - room => { +test(`create room [creates Alice's new room]`, t => { + fetchUser(t, 'alice') + .then(alice => alice.createRoom({ name: `Alice's new room` })) + .then(room => { alicesRoom = room t.equal(room.name, `Alice's new room`) t.false(room.isPrivate, `room shouldn't be private`) t.equal(room.createdByUserId, 'alice') t.deepEqual(room.userIds, ['alice']) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create private room [creates Alice's private room]`, t => { - fetchUser(t, 'alice').then(alice => alice.createRoom( - { name: `Alice's private room`, private: true }, - room => { +test(`create private room [creates Alice's private room]`, t => { + fetchUser(t, 'alice') + .then(alice => alice.createRoom({ + name: `Alice's private room`, + private: true + })) + .then(room => { alicesPrivateRoom = room t.equal(room.name, `Alice's private room`) t.true(room.isPrivate, 'room should be private') t.equal(room.createdByUserId, 'alice') t.deepEqual(room.userIds, ['alice']) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create room with members [creates Bob's new room]`, t => { - fetchUser(t, 'bob').then(bob => bob.createRoom( - { name: `Bob's new room`, addUserIds: ['alice'] }, - room => { +test(`create room with members [creates Bob's new room]`, t => { + fetchUser(t, 'bob') + .then(bob => bob.createRoom({ + name: `Bob's new room`, + addUserIds: ['alice'] + })) + .then(room => { bobsRoom = room t.equal(room.name, `Bob's new room`) t.false(room.isPrivate, `room shouldn't be private`) t.equal(room.createdByUserId, 'bob') t.deepEqual(room.userIds.sort(), ['alice', 'bob']) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 79f37b1a4c71c0111be8b316962f8ba5d64a562c Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 15:37:03 +0000 Subject: [PATCH 20/99] getJoinableRooms --- src/current-user.js | 14 ++++++++++++++ tests/main.js | 24 +++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index d8ca914..104e979 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -85,6 +85,20 @@ export class CurrentUser { }) } + getJoinableRooms () { + // TODO path friendly ids everywhere + return this.apiInstance + .request({ + method: 'GET', + path: `/users/${this.id}/rooms?joinable=true` + }) + .then(pipe(JSON.parse, map(parseBasicRoom))) + .catch(err => { + this.logger.warning('error getting joinable rooms:', err) + throw err + }) + } + /* internal */ establishUserSubscription = hooks => { diff --git a/tests/main.js b/tests/main.js index 5dd6cff..63f05d6 100644 --- a/tests/main.js +++ b/tests/main.js @@ -423,22 +423,21 @@ test(`create room with members [creates Bob's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('get joined rooms', t => { +test('get joined rooms', t => { const expectedRoomIds = [alicesRoom, bobsRoom, alicesPrivateRoom] .map(r => r.id).sort() - fetchUser(t, 'alice').then(alice => alice.getJoinedRooms( - rooms => { - t.deepEqual(rooms.map(r => r.id).sort(), expectedRoomIds) + fetchUser(t, 'alice') + .then(alice => { + t.deepEqual(map(r => r.id, alice.rooms).sort(), expectedRoomIds) t.end() - }, - endWithErr(t) - )) + }) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('get joinable rooms', t => { - fetchUser(t, 'bob').then(bob => bob.getJoinableRooms( - rooms => { +test('get joinable rooms', t => { + fetchUser(t, 'bob') + .then(bob => bob.getJoinableRooms()) + .then(rooms => { const ids = rooms.map(r => r.id) t.true(ids.includes(alicesRoom.id), `should include Alice's room`) t.false(ids.includes(bobsRoom.id), `shouldn't include Bob's room`) @@ -447,9 +446,8 @@ test.skip('get joinable rooms', t => { `shouldn't include Alice's private room` ) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 7f83f5b88104fcab4d927836ab389c70b71d0f57 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 15:47:22 +0000 Subject: [PATCH 21/99] getAllRooms --- src/current-user.js | 11 ++++++++--- tests/main.js | 16 ++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 104e979..bd25f5b 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,5 +1,6 @@ import { chain, + concat, indexBy, join, length, @@ -52,12 +53,12 @@ export class CurrentUser { return values(this.userStore.snapshot()) } - isTypingIn (roomId) { + isTypingIn = (roomId) => { typeCheck('roomId', 'number', roomId) return this.typingIndicators.sendThrottledRequest(roomId) } - createRoom (options = {}) { + createRoom = (options = {}) => { typeCheck('options', 'object', options) if (options.name !== undefined) { typeCheck('name', 'string', options.name) @@ -85,7 +86,7 @@ export class CurrentUser { }) } - getJoinableRooms () { + getJoinableRooms = () => { // TODO path friendly ids everywhere return this.apiInstance .request({ @@ -99,6 +100,10 @@ export class CurrentUser { }) } + getAllRooms = () => { + return this.getJoinableRooms().then(concat(this.rooms)) + } + /* internal */ establishUserSubscription = hooks => { diff --git a/tests/main.js b/tests/main.js index 63f05d6..11b7bb0 100644 --- a/tests/main.js +++ b/tests/main.js @@ -451,13 +451,10 @@ test('get joinable rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME -test.skip('get all rooms', t => { - // Currently slightly broken because the /rooms route only returns 20 rooms - // by default, and there's no way to hook in to the pagination via this - // method. - fetchUser(t, 'bob').then(bob => bob.getAllRooms( - rooms => { +test('get all rooms', t => { + fetchUser(t, 'bob') + .then(bob => bob.getAllRooms()) + .then(rooms => { const ids = rooms.map(r => r.id) t.true(ids.includes(alicesRoom.id), `should include Alice's room`) t.true(ids.includes(bobsRoom.id), `should include Bob's room`) @@ -466,9 +463,8 @@ test.skip('get all rooms', t => { `shouldn't include Alice's private room` ) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From b4c0f439f348acccb6a315525d1cb56846571f22 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 16:06:29 +0000 Subject: [PATCH 22/99] join room --- src/current-user.js | 18 ++++++++++++++++++ tests/main.js | 30 +++++++++++++++--------------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index bd25f5b..7643a20 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -77,6 +77,7 @@ export class CurrentUser { } }) .then(res => { + // TODO grab user details const basicRoom = parseBasicRoom(JSON.parse(res)) return this.roomStore.set(basicRoom.id, basicRoom) }) @@ -104,6 +105,23 @@ export class CurrentUser { return this.getJoinableRooms().then(concat(this.rooms)) } + joinRoom = roomId => { + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'POST', + path: `/users/${this.id}/rooms/${roomId}/join` + }) + .then(res => { + // TODO grab user details + const basicRoom = parseBasicRoom(JSON.parse(res)) + return this.roomStore.set(basicRoom.id, basicRoom) + }) + .catch(err => { + this.logger.warning(`error joining room ${roomId}:`, err) + }) + } + /* internal */ establishUserSubscription = hooks => { diff --git a/tests/main.js b/tests/main.js index 11b7bb0..d091621 100644 --- a/tests/main.js +++ b/tests/main.js @@ -468,21 +468,21 @@ test('get all rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`join room [Bob joins Alice's room]`, t => { - fetchUser(t, 'bob').then(bob => bob.joinRoom( - alicesRoom.id, - room => { - t.equal(room.id, alicesRoom.id) - t.equal(room.createdByUserId, 'alice') - t.true(room.userIds.includes('bob'), 'should include bob') - t.true( - any(r => r.id === alicesRoom.id, bob.rooms), - `should include Alice's room` - ) - t.end() - }, - endWithErr(t) - )) +test(`join room [Bob joins Alice's room]`, t => { + fetchUser(t, 'bob') + .then(bob => bob.joinRoom(alicesRoom.id) + .then(room => { + t.equal(room.id, alicesRoom.id) + t.equal(room.createdByUserId, 'alice') + t.true(room.userIds.includes('bob'), 'should include bob') + t.true( + any(r => r.id === alicesRoom.id, bob.rooms), + `should include Alice's room` + ) + t.end() + }) + ) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 0084f070afca9402a25fa85b20316f69c3068ac9 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 17:27:44 +0000 Subject: [PATCH 23/99] fetch user details in bulk every time a room is set or updated --- src/current-user.js | 35 ++++++++++------------------------- src/room-store.js | 8 +++++++- src/room.js | 8 +++++--- src/store.js | 2 +- src/user-store.js | 24 +++++++++++++++++++++++- src/user-subscription.js | 1 - tests/main.js | 27 ++++++++++++++------------- 7 files changed, 60 insertions(+), 45 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 7643a20..02ee08b 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -2,8 +2,6 @@ import { chain, concat, indexBy, - join, - length, map, pipe, prop, @@ -11,11 +9,11 @@ import { values } from 'ramda' -import { appendQueryParam, typeCheck, typeCheckArr } from './utils' +import { typeCheck, typeCheckArr } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseUser, parseBasicRoom } from './parsers' +import { parseBasicRoom } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' @@ -77,12 +75,11 @@ export class CurrentUser { } }) .then(res => { - // TODO grab user details const basicRoom = parseBasicRoom(JSON.parse(res)) return this.roomStore.set(basicRoom.id, basicRoom) }) .catch(err => { - this.logger.warning('error creating room:', err) + this.logger.warn('error creating room:', err) throw err }) } @@ -96,7 +93,7 @@ export class CurrentUser { }) .then(pipe(JSON.parse, map(parseBasicRoom))) .catch(err => { - this.logger.warning('error getting joinable rooms:', err) + this.logger.warn('error getting joinable rooms:', err) throw err }) } @@ -113,12 +110,11 @@ export class CurrentUser { path: `/users/${this.id}/rooms/${roomId}/join` }) .then(res => { - // TODO grab user details const basicRoom = parseBasicRoom(JSON.parse(res)) return this.roomStore.set(basicRoom.id, basicRoom) }) .catch(err => { - this.logger.warning(`error joining room ${roomId}:`, err) + this.logger.warn(`error joining room ${roomId}:`, err) }) } @@ -155,24 +151,13 @@ export class CurrentUser { } initializeUserStore = () => { - const userIds = uniq(chain(prop('userIds'), this.rooms)) - if (length(userIds) === 0) { - this.userStore.initialize({}) - return - } - return this.apiInstance - .request({ - method: 'GET', - path: appendQueryParam('user_ids', join(',', userIds), '/users_by_ids') - }) - .then(pipe( - JSON.parse, - map(parseUser), - indexBy(prop('id')), - this.userStore.initialize - )) + return this.userStore.fetchMissingUsers( + uniq(chain(prop('userIds'), this.rooms)) + ) .catch(err => { this.logger.warn('error fetching initial user information:', err) + }) + .then(() => { this.userStore.initialize({}) }) } diff --git a/src/room-store.js b/src/room-store.js index 72e2efc..0e7e901 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -15,7 +15,13 @@ export class RoomStore { initialize = this.store.initialize - set = (key, value) => this.store.set(key, value).then(this.decorate) + set = (roomId, basicRoom) => { + return this.store.set(roomId, basicRoom) + .then(this.decorate) + .then(room => + this.userStore.fetchMissingUsers(room.userIds).then(() => room) + ) + } get = roomId => this.store.get(roomId).then(basicRoom => basicRoom || this.fetchBasicRoom(roomId) diff --git a/src/room.js b/src/room.js index f35294c..3c24099 100644 --- a/src/room.js +++ b/src/room.js @@ -1,4 +1,4 @@ -import { contains, filter, map, values } from 'ramda' +import { map, contains, filter, values } from 'ramda' export class Room { constructor (basicRoom, userStore) { @@ -13,9 +13,11 @@ export class Room { this.userStore = userStore } - getUsers = () => Promise.all(map(this.userStore.get, this.userIds)) - get users () { + console.log(`userIds = ${JSON.stringify(this.userIds)}`) + console.log(`userStore ids = ${ + JSON.stringify(map(user => user.id, values(this.userStore.snapshot()))) + }`) return filter( user => contains(user.id, this.userIds), values(this.userStore.snapshot()) diff --git a/src/store.js b/src/store.js index 39a7268..eb9bccb 100644 --- a/src/store.js +++ b/src/store.js @@ -39,5 +39,5 @@ export class Store { return value }) - snapshot = () => this.store + snapshot = () => this.store || {} } diff --git a/src/user-store.js b/src/user-store.js index ff3a49a..d1c6ef1 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -1,5 +1,6 @@ -import { map } from 'ramda' +import { difference, join, length, map, pipe, prop, forEach } from 'ramda' +import { appendQueryParam } from './utils' import { Store } from './store' import { parseUser } from './parsers' @@ -38,6 +39,27 @@ export class UserStore { }) } + fetchMissingUsers = userIds => { + const missing = difference(userIds, map(prop('id'), this.store.snapshot())) + if (length(missing) === 0) { + return Promise.resolve() + } + return this.instance + .request({ + method: 'GET', + path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') + }) + .then(pipe( + JSON.parse, + map(parseUser), + forEach(user => this.set(user.id, user)) + )) + .catch(err => { + this.logger.warn('error fetching missing users:', err) + throw err + }) + } + snapshot = () => { const presenceSnapshot = this.presenceStore.snapshot() return map( diff --git a/src/user-subscription.js b/src/user-subscription.js index 6d7c4a6..9cedd4b 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -62,7 +62,6 @@ export class UserSubscription { } onAddedToRoom = ({ room: roomData }) => { - // TODO fetch new user details in bulk when added to room const basicRoom = parseBasicRoom(roomData) this.roomStore.set(basicRoom.id, basicRoom).then(room => { if (this.hooks.addedToRoom) { diff --git a/tests/main.js b/tests/main.js index d091621..b4ea553 100644 --- a/tests/main.js +++ b/tests/main.js @@ -68,7 +68,14 @@ const concatBatch = (n, f) => batch(n, compose(f, reduce(concat, []))) const fetchUser = (t, userId, hooks = {}) => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId, - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }), + logger: { + error: console.log, + warn: console.log, + info: () => {}, + debug: () => {}, + verbose: () => {} + } }).connect(map(once, hooks)).catch(endWithErr(t)) const endWithErr = curry((t, err) => t.end(`error: ${toString(err)}`)) @@ -211,12 +218,10 @@ test('connection resolves with current user object', t => { t.equal(alice.rooms[0].isPrivate, false) t.equal(alice.rooms[0].createdByUserId, 'alice') t.deepEqual(alice.rooms[0].userIds, ['alice']) - alice.rooms[0].getUsers().then(users => { - t.true(Array.isArray(users), 'users is an array') - t.equal(length(users), 1) - t.equal(users[0].name, 'Alice') - t.end() - }).catch(endWithErr(t)) + t.true(Array.isArray(alice.rooms[0].users), 'users is an array') + t.equal(length(alice.rooms[0].users), 1) + t.equal(alice.rooms[0].users[0].name, 'Alice') + t.end() }) t.timeoutAfter(TEST_TIMEOUT) }) @@ -234,12 +239,8 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { ) const br = find(r => r.id === room.id, alice.rooms) t.true(br, `alice.rooms should contain Bob's room`) - br.getUsers() - .then(users => { - t.deepEqual(map(prop('name'), users).sort(), ['Alice', 'Bob']) - t.end() - }) - .catch(endWithErr(t)) + t.deepEqual(map(prop('name'), br.users).sort(), ['Alice', 'Bob']) + t.end() } }) .then(a => { alice = a }) From fea38ce05bd73af025e1393567336fe5fc64cb20 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 8 Feb 2018 17:50:30 +0000 Subject: [PATCH 24/99] leaveRoom --- src/current-user.js | 14 ++++++++++++++ src/room.js | 6 +----- src/user-subscription.js | 2 +- tests/main.js | 24 ++++++++++++++---------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 02ee08b..63ef8f8 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -115,6 +115,20 @@ export class CurrentUser { }) .catch(err => { this.logger.warn(`error joining room ${roomId}:`, err) + throw err + }) + } + + leaveRoom = roomId => { + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'POST', + path: `/users/${this.id}/rooms/${roomId}/leave` + }) + .catch(err => { + this.logger.warn(`error joining room ${roomId}:`, err) + throw err }) } diff --git a/src/room.js b/src/room.js index 3c24099..fbdac10 100644 --- a/src/room.js +++ b/src/room.js @@ -1,4 +1,4 @@ -import { map, contains, filter, values } from 'ramda' +import { contains, filter, values } from 'ramda' export class Room { constructor (basicRoom, userStore) { @@ -14,10 +14,6 @@ export class Room { } get users () { - console.log(`userIds = ${JSON.stringify(this.userIds)}`) - console.log(`userStore ids = ${ - JSON.stringify(map(user => user.id, values(this.userStore.snapshot()))) - }`) return filter( user => contains(user.id, this.userIds), values(this.userStore.snapshot()) diff --git a/src/user-subscription.js b/src/user-subscription.js index 9cedd4b..e0766a0 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -72,7 +72,7 @@ export class UserSubscription { onRemovedFromRoom = ({ room_id: roomId }) => { this.roomStore.pop(roomId).then(room => { - if (this.hooks.removedFromRoom) { + if (room && this.hooks.removedFromRoom) { this.hooks.removedFromRoom(room) } }) diff --git a/tests/main.js b/tests/main.js index b4ea553..831aaaa 100644 --- a/tests/main.js +++ b/tests/main.js @@ -487,18 +487,22 @@ test(`join room [Bob joins Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`leave room [Bob leaves Alice's room]`, t => { - fetchUser(t, 'bob').then(bob => bob.leaveRoom( - alicesRoom.id, - () => setTimeout(() => { - t.false( +test(`leave room [Bob leaves Alice's room]`, t => { + fetchUser(t, 'bob') + .then(bob => { + t.true( any(r => r.id === alicesRoom.id, bob.rooms), - `shouldn't include Alice's room` + `should include Bob's room` ) - t.end() - }, 1000), // FIXME should work without the timeout - endWithErr(t) - )) + bob.leaveRoom(alicesRoom.id) + .then(() => { + t.false( + any(r => r.id === alicesRoom.id, bob.rooms), + `shouldn't include Alice's room` + ) + t.end() + }) + }) t.timeoutAfter(TEST_TIMEOUT) }) From cb9d857dd0e7f9abf67e9f4179ec65aac271eb8b Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 10:04:17 +0000 Subject: [PATCH 25/99] remove room from store on leaveRoom, don't fire removedFromRoom --- src/current-user.js | 1 + src/user-subscription.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/current-user.js b/src/current-user.js index 63ef8f8..2a796e6 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -126,6 +126,7 @@ export class CurrentUser { method: 'POST', path: `/users/${this.id}/rooms/${roomId}/leave` }) + .then(() => this.roomStore.pop(roomId)) .catch(err => { this.logger.warn(`error joining room ${roomId}:`, err) throw err diff --git a/src/user-subscription.js b/src/user-subscription.js index e0766a0..456f615 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -72,6 +72,7 @@ export class UserSubscription { onRemovedFromRoom = ({ room_id: roomId }) => { this.roomStore.pop(roomId).then(room => { + // room will be undefined if we left with leaveRoom if (room && this.hooks.removedFromRoom) { this.hooks.removedFromRoom(room) } From b3ec037ba00537ddd3d59f798ad16abb54cd1cf4 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 10:25:15 +0000 Subject: [PATCH 26/99] add user, remove user --- src/current-user.js | 39 +++++++++++++++++++++++++++++++++++++++ tests/main.js | 42 ++++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 2a796e6..cbdcc23 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -133,6 +133,45 @@ export class CurrentUser { }) } + addUser = (userId, roomId) => { + typeCheck('userId', 'string', userId) + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'PUT', + path: `/rooms/${roomId}/users/add`, + json: { + user_ids: [userId] + } + }) + .then(() => this.roomStore.addUserToRoom(roomId, userId)) + .catch(err => { + this.logger.warn(`error adding user ${userId} to room ${roomId}:`, err) + throw err + }) + } + + removeUser = (userId, roomId) => { + typeCheck('userId', 'string', userId) + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'PUT', + path: `/rooms/${roomId}/users/remove`, + json: { + user_ids: [userId] + } + }) + .then(() => this.roomStore.removeUserFromRoom(roomId, userId)) + .catch(err => { + this.logger.warn( + `error removing user ${userId} from room ${roomId}:`, + err + ) + throw err + }) + } + /* internal */ establishUserSubscription = hooks => { diff --git a/tests/main.js b/tests/main.js index 831aaaa..9e07cf3 100644 --- a/tests/main.js +++ b/tests/main.js @@ -506,31 +506,29 @@ test(`leave room [Bob leaves Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('add user [Alice adds Bob to her room]', t => { - fetchUser(t, 'alice').then(alice => alice.addUser( - 'bob', - alicesRoom.id, - () => setTimeout(() => { - const room = alice.rooms.find(r => r.id === alicesRoom.id) - t.deepEqual(room.userIds.sort(), ['alice', 'bob']) - t.end() - }, 1000), // FIXME should work without the timeout - endWithErr(t) - )) +test('add user [Alice adds Bob to her room]', t => { + fetchUser(t, 'alice') + .then(alice => alice.addUser('bob', alicesRoom.id) + .then(() => { + const room = find(r => r.id === alicesRoom.id, alice.rooms) + t.deepEqual(room.userIds.sort(), ['alice', 'bob']) + t.end() + }) + .catch(endWithErr(t)) + ) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('remove user [Alice removes Bob from her room]', t => { - fetchUser(t, 'alice').then(alice => alice.removeUser( - 'bob', - alicesRoom.id, - () => setTimeout(() => { - const room = alice.rooms.find(r => r.id === alicesRoom.id) - t.deepEqual(room.userIds.sort(), ['alice']) - t.end() - }, 1000), // FIXME should work without the timeout - endWithErr(t) - )) +test('remove user [Alice removes Bob from her room]', t => { + fetchUser(t, 'alice') + .then(alice => alice.removeUser('bob', alicesRoom.id) + .then(() => { + const room = find(r => r.id === alicesRoom.id, alice.rooms) + t.deepEqual(room.userIds.sort(), ['alice']) + t.end() + }) + .catch(endWithErr(t)) + ) t.timeoutAfter(TEST_TIMEOUT) }) From d0d18f468649f26490ecd3e414ae8df31b741303 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 10:29:30 +0000 Subject: [PATCH 27/99] remove redundant call to roomStore in user sub handlers --- src/user-subscription.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/user-subscription.js b/src/user-subscription.js index 456f615..9c58ea4 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -80,24 +80,22 @@ export class UserSubscription { } onUserJoined = ({ room_id: roomId, user_id: userId }) => { - this.roomStore.addUserToRoom(roomId, userId).then(() => { - Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => { - if (this.hooks.userJoinedRoom) { - this.hooks.userJoinedRoom(r, u) - } - }) + this.roomStore.addUserToRoom(roomId, userId).then(room => { + this.userStore.get(userId).then(user => { + if (this.hooks.userJoinedRoom) { + this.hooks.userJoinedRoom(room, user) + } + }) }) } onUserLeft = ({ room_id: roomId, user_id: userId }) => { - this.roomStore.removeUserFromRoom(roomId, userId).then(() => { - Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => { - if (this.hooks.userLeftRoom) { - this.hooks.userLeftRoom(r, u) - } - }) + this.roomStore.removeUserFromRoom(roomId, userId).then(room => { + this.userStore.get(userId).then(user => { + if (this.hooks.userLeftRoom) { + this.hooks.userLeftRoom(room, user) + } + }) }) } From 85eb0dcbd023f74b495ed266e4cc26aedc9e341f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 10:59:02 +0000 Subject: [PATCH 28/99] basic sendMessage --- src/current-user.js | 19 ++++++++++++++++++- tests/main.js | 9 +++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index cbdcc23..bf1eee7 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -57,7 +57,7 @@ export class CurrentUser { } createRoom = (options = {}) => { - typeCheck('options', 'object', options) + typeCheck('create room options', 'object', options) if (options.name !== undefined) { typeCheck('name', 'string', options.name) } @@ -172,6 +172,23 @@ export class CurrentUser { }) } + // TODO attachments + sendMessage = ({ text, roomId } = {}) => { + typeCheck('text', 'string', text) + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'POST', + path: `/rooms/${roomId}/messages`, + json: { text } + }) + .then(pipe(JSON.parse, prop('message_id'))) + .catch(err => { + this.logger.warn(`error sending message to room ${roomId}:`, err) + throw err + }) + } + /* internal */ establishUserSubscription = hooks => { diff --git a/tests/main.js b/tests/main.js index 9e07cf3..8cc1e62 100644 --- a/tests/main.js +++ b/tests/main.js @@ -80,12 +80,9 @@ const fetchUser = (t, userId, hooks = {}) => new ChatManager({ const endWithErr = curry((t, err) => t.end(`error: ${toString(err)}`)) -const sendMessage = (user, room, text) => new Promise((resolve, reject) => - user.sendMessage({ roomId: room.id, text }, resolve, reject)) - const sendMessages = (user, room, texts) => length(texts) === 0 ? Promise.resolve() - : sendMessage(user, room, head(texts)) + : user.sendMessage({ roomId: room.id, text: head(texts) }) .then(() => sendMessages(user, room, tail(texts))) // Imports @@ -532,12 +529,12 @@ test('remove user [Alice removes Bob from her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`send message [sends four messages to Bob's room]`, t => { +test(`send message [sends four messages to Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => sendMessages(alice, bobsRoom, [ 'hello', 'hey', 'hi', 'ho' ])) - .then(() => t.end()) + .then(t.end) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From e30060a7cfda919ae77f0ddab88a2b38b5980be5 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 12:33:46 +0000 Subject: [PATCH 29/99] basic fetch messages --- src/current-user.js | 32 +++++++++++++++++++++++++++++++- src/message.js | 20 ++++++++++++++++++++ src/parsers.js | 9 +++++++++ src/room-store.js | 2 ++ src/store.js | 2 ++ src/user-store.js | 12 ++++++++++++ tests/main.js | 14 ++++++-------- 7 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 src/message.js diff --git a/src/current-user.js b/src/current-user.js index bf1eee7..7424968 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,10 +1,12 @@ import { chain, + compose, concat, indexBy, map, pipe, prop, + sort, uniq, values } from 'ramda' @@ -13,10 +15,11 @@ import { typeCheck, typeCheckArr } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseBasicRoom } from './parsers' +import { parseBasicRoom, parseBasicMessage } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' +import { Message } from './message' export class CurrentUser { constructor ({ id, apiInstance }) { @@ -176,6 +179,7 @@ export class CurrentUser { sendMessage = ({ text, roomId } = {}) => { typeCheck('text', 'string', text) typeCheck('roomId', 'number', roomId) + console.log(`SENDING MESSAGE ${text}`) return this.apiInstance .request({ method: 'POST', @@ -189,8 +193,34 @@ export class CurrentUser { }) } + fetchMessages = roomId => { + typeCheck('roomId', 'number', roomId) + return this.apiInstance + .request({ + method: 'GET', + path: `/rooms/${roomId}/messages` + }) + .then(res => { + const messages = + map(compose(this.decorateMessage, parseBasicMessage), JSON.parse(res)) + return this.userStore.fetchMissingUsers( + uniq(map(prop('senderId'), messages)) + ).then(() => sort((x, y) => x.id - y.id, messages)) + }) + .catch(err => { + this.logger.warn(`error fetching messages from room ${roomId}:`, err) + throw err + }) + } + /* internal */ + decorateMessage = basicMessage => new Message( + basicMessage, + this.userStore, + this.roomStore + ) + establishUserSubscription = hooks => { this.userSubscription = new UserSubscription({ hooks, diff --git a/src/message.js b/src/message.js new file mode 100644 index 0000000..930fc96 --- /dev/null +++ b/src/message.js @@ -0,0 +1,20 @@ +export class Message { + constructor (basicMessage, userStore, roomStore) { + this.id = basicMessage.id + this.senderId = basicMessage.senderId + this.roomId = basicMessage.roomId + this.text = basicMessage.text + this.createdAt = basicMessage.createdAt + this.updatedAt = basicMessage.updatedAt + this.userStore = userStore + this.roomStore = roomStore + } + + get sender () { + return this.userStore.getSync(this.senderId) + } + + get room () { + return this.roomStore.getSync(this.roomId) + } +} diff --git a/src/parsers.js b/src/parsers.js index ac97863..14e217f 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -25,3 +25,12 @@ export const parsePresenceState = data => ({ state: contains(data.state, ['online', 'offline']) ? data.state : 'unknown', userId: data.user_id }) + +export const parseBasicMessage = data => ({ + id: data.id, + senderId: data.user_id, + roomId: data.room_id, + text: data.text, + createdAt: data.created_at, + updatedAt: data.updated_at +}) diff --git a/src/room-store.js b/src/room-store.js index 0e7e901..696465b 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -63,4 +63,6 @@ export class RoomStore { : undefined snapshot = () => map(this.decorate, this.store.snapshot()) + + getSync = key => this.decorate(this.store.getSync(key)) } diff --git a/src/store.js b/src/store.js index eb9bccb..f043ff7 100644 --- a/src/store.js +++ b/src/store.js @@ -40,4 +40,6 @@ export class Store { }) snapshot = () => this.store || {} + + getSync = key => this.store ? this.store[key] : undefined } diff --git a/src/user-store.js b/src/user-store.js index d1c6ef1..48906ef 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -60,6 +60,7 @@ export class UserStore { }) } + // TODO move decoration with presence in to a decorator function snapshot = () => { const presenceSnapshot = this.presenceStore.snapshot() return map( @@ -67,4 +68,15 @@ export class UserStore { this.store.snapshot() ) } + + getSync = userId => { + const user = this.store.getSync(userId) + if (user === undefined) { + return undefined + } + return { + ...user, + presence: this.presenceStore.getSync(userId) + } + } } diff --git a/tests/main.js b/tests/main.js index 8cc1e62..ca1a3a8 100644 --- a/tests/main.js +++ b/tests/main.js @@ -539,20 +539,18 @@ test(`send message [sends four messages to Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('fetch messages', t => { - fetchUser(t, 'alice').then(alice => alice.fetchMessagesFromRoom( - bobsRoom, // TODO why is this room, and send message etc is roomId? - {}, - messages => { +test('fetch messages', t => { + fetchUser(t, 'alice') + .then(alice => alice.fetchMessages(bobsRoom.id)) + .then(messages => { t.deepEqual(messages.map(m => m.text), ['hello', 'hey', 'hi', 'ho']) t.equal(messages[0].sender.id, 'alice') t.equal(messages[0].sender.name, 'Alice') t.equal(messages[0].room.id, bobsRoom.id) t.equal(messages[0].room.name, bobsRoom.name) t.end() - }, - endWithErr(t) - )) + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 2cdce74e44a0e8e5468a4a3d75b49ab3d647f309 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 14:05:12 +0000 Subject: [PATCH 30/99] fetchMessages with extra options --- src/current-user.js | 31 ++++++++++++++++--------------- src/utils.js | 9 +++++++++ tests/main.js | 36 +++++++++++++----------------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 7424968..217e793 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -11,7 +11,7 @@ import { values } from 'ramda' -import { typeCheck, typeCheckArr } from './utils' +import { urlEncode, typeCheck, typeCheckArr, checkOneOf } from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' @@ -59,22 +59,17 @@ export class CurrentUser { return this.typingIndicators.sendThrottledRequest(roomId) } - createRoom = (options = {}) => { - typeCheck('create room options', 'object', options) - if (options.name !== undefined) { - typeCheck('name', 'string', options.name) - } - if (options.addUserIds !== undefined) { - typeCheckArr('addUserIds', 'string', options.addUserIds) - } + createRoom = ({ name, addUserIds, ...rest } = {}) => { + name && typeCheck('name', 'string', name) + addUserIds && typeCheckArr('addUserIds', 'string', addUserIds) return this.apiInstance.request({ method: 'POST', path: '/rooms', json: { created_by_id: this.id, - name: options.name, - private: !!options.private, - user_ids: options.addUserIds + name, + private: !!rest.private, // private is a reserved word in strict mode! + user_ids: addUserIds } }) .then(res => { @@ -179,7 +174,6 @@ export class CurrentUser { sendMessage = ({ text, roomId } = {}) => { typeCheck('text', 'string', text) typeCheck('roomId', 'number', roomId) - console.log(`SENDING MESSAGE ${text}`) return this.apiInstance .request({ method: 'POST', @@ -193,12 +187,19 @@ export class CurrentUser { }) } - fetchMessages = roomId => { + fetchMessages = (roomId, { initialId, limit, direction } = {}) => { typeCheck('roomId', 'number', roomId) + initialId && typeCheck('initialId', 'number', initialId) + limit && typeCheck('limit', 'number', limit) + direction && checkOneOf('direction', ['older', 'newer'], direction) return this.apiInstance .request({ method: 'GET', - path: `/rooms/${roomId}/messages` + path: `/rooms/${roomId}/messages?${urlEncode({ + initial_id: initialId, + limit, + direction + })}` }) .then(res => { const messages = diff --git a/src/utils.js b/src/utils.js index a36c3e9..430250c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,5 @@ import { + contains, filter, forEachObjIndexed, join, @@ -45,6 +46,14 @@ export const typeCheckObj = (name, expectedType, obj) => { forEachObjIndexed((value, key) => typeCheck(key, expectedType, value), obj) } +export const checkOneOf = (name, values, value) => { + if (!contains(value, values)) { + throw new TypeError( + `expected ${name} to be one of ${values} but was ${value}` + ) + } +} + // pointfree debugging export const trace = msg => x => { console.log(msg, x) diff --git a/tests/main.js b/tests/main.js index ca1a3a8..e514690 100644 --- a/tests/main.js +++ b/tests/main.js @@ -554,30 +554,20 @@ test('fetch messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('fetch messages with pagination', t => { +test('fetch messages with pagination', t => { fetchUser(t, 'alice') - .then(alice => new Promise(resolve => { - alice.fetchMessagesFromRoom( - bobsRoom, - { limit: 2 }, - messages => { - t.deepEqual(messages.map(m => m.text), ['hi', 'ho']) - resolve([alice, messages[0].id]) - }, - endWithErr(t) - ) - })) - .then(([alice, initialId]) => { - alice.fetchMessagesFromRoom( - bobsRoom, - { initialId }, - messages => { - t.deepEqual(messages.map(m => m.text), ['hello', 'hey']) - t.end() - }, - endWithErr(t) - ) - }) + .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 2 }) + .then(messages => { + t.deepEqual(messages.map(m => m.text), ['hi', 'ho']) + return messages[0].id + }) + .then(initialId => alice.fetchMessages(bobsRoom.id, { initialId })) + .then(messages => { + t.deepEqual(messages.map(m => m.text), ['hello', 'hey']) + t.end() + }) + ) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 3889430558c02e92784fd6827f6357a12f48f1b3 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 14:36:56 +0000 Subject: [PATCH 31/99] decorators and comments about getSync and snapshot --- src/room-store.js | 8 ++++---- src/store.js | 4 ++++ src/user-store.js | 24 +++++++----------------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/room-store.js b/src/room-store.js index 696465b..e26ad36 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -58,11 +58,11 @@ export class RoomStore { }) } - decorate = basicRoom => basicRoom - ? new Room(basicRoom, this.userStore) - : undefined - snapshot = () => map(this.decorate, this.store.snapshot()) getSync = key => this.decorate(this.store.getSync(key)) + + decorate = basicRoom => basicRoom + ? new Room(basicRoom, this.userStore) + : undefined } diff --git a/src/store.js b/src/store.js index f043ff7..22cf78e 100644 --- a/src/store.js +++ b/src/store.js @@ -39,6 +39,10 @@ export class Store { return value }) + // snapshot and getSync are useful for building synchronous interfaces, but + // should only be used when we can guarantee that the information we want is + // already in the store (i.e. we've just done an explicit fetch) + snapshot = () => this.store || {} getSync = key => this.store ? this.store[key] : undefined diff --git a/src/user-store.js b/src/user-store.js index 48906ef..c1e01d5 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -60,23 +60,13 @@ export class UserStore { }) } - // TODO move decoration with presence in to a decorator function - snapshot = () => { - const presenceSnapshot = this.presenceStore.snapshot() - return map( - user => ({ ...user, presence: presenceSnapshot[user.id] }), - this.store.snapshot() - ) - } + snapshot = () => map(this.decorate, this.store.snapshot()) - getSync = userId => { - const user = this.store.getSync(userId) - if (user === undefined) { - return undefined - } - return { - ...user, - presence: this.presenceStore.getSync(userId) - } + getSync = userId => this.decorate(this.store.getSync(userId)) + + decorate = user => { + return user + ? { ...user, presence: this.presenceStore.getSync(user.id) } + : undefined } } From a77b62a309e45a96fbf8c93dded43bff14ebdbf1 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 16:13:30 +0000 Subject: [PATCH 32/99] room subscription --- src/current-user.js | 32 +++++++++++++++++-- src/room-store.js | 10 +++--- src/room-subscription.js | 66 ++++++++++++++++++++++++++++++++++++++ tests/main.js | 68 +++++++++++++++++++++------------------- 4 files changed, 136 insertions(+), 40 deletions(-) create mode 100644 src/room-subscription.js diff --git a/src/current-user.js b/src/current-user.js index 217e793..fe9d48d 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -11,7 +11,13 @@ import { values } from 'ramda' -import { urlEncode, typeCheck, typeCheckArr, checkOneOf } from './utils' +import { + checkOneOf, + typeCheck, + typeCheckArr, + typeCheckObj, + urlEncode +} from './utils' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' @@ -19,6 +25,7 @@ import { parseBasicRoom, parseBasicMessage } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' +import { RoomSubscription } from './room-subscription' import { Message } from './message' export class CurrentUser { @@ -42,6 +49,7 @@ export class CurrentUser { instance: this.apiInstance, logger: this.logger }) + this.roomSubscriptions = {} } /* public */ @@ -202,8 +210,10 @@ export class CurrentUser { })}` }) .then(res => { - const messages = - map(compose(this.decorateMessage, parseBasicMessage), JSON.parse(res)) + const messages = map( + compose(this.decorateMessage, parseBasicMessage), + JSON.parse(res) + ) return this.userStore.fetchMissingUsers( uniq(map(prop('senderId'), messages)) ).then(() => sort((x, y) => x.id - y.id, messages)) @@ -214,6 +224,22 @@ export class CurrentUser { }) } + subscribeToRoom = (roomId, hooks = {}, messageLimit) => { + typeCheck('roomId', 'number', roomId) + typeCheckObj('hooks', 'function', hooks) + messageLimit && typeCheck('messageLimit', 'number', messageLimit) + this.roomSubscriptions[roomId] = new RoomSubscription({ + roomId, + hooks, + messageLimit, + userId: this.id, + instance: this.apiInstance, + userStore: this.userStore, + roomStore: this.roomStore + }) + return this.roomSubscriptions[roomId].connect() + } + /* internal */ decorateMessage = basicMessage => new Message( diff --git a/src/room-store.js b/src/room-store.js index e26ad36..897a881 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -60,9 +60,11 @@ export class RoomStore { snapshot = () => map(this.decorate, this.store.snapshot()) - getSync = key => this.decorate(this.store.getSync(key)) + getSync = roomId => this.decorate(this.store.getSync(roomId)) - decorate = basicRoom => basicRoom - ? new Room(basicRoom, this.userStore) - : undefined + decorate = basicRoom => { + return basicRoom + ? new Room(basicRoom, this.userStore) + : undefined + } } diff --git a/src/room-subscription.js b/src/room-subscription.js new file mode 100644 index 0000000..6b794a2 --- /dev/null +++ b/src/room-subscription.js @@ -0,0 +1,66 @@ +import { head, isEmpty } from 'ramda' + +import { parseBasicMessage } from './parsers' +import { urlEncode } from './utils' +import { Message } from './message' + +export class RoomSubscription { + constructor (options) { + this.roomId = options.roomId + this.hooks = options.hooks + this.messageLimit = options.messageLimit + this.userId = options.userId + this.instance = options.instance + this.userStore = options.userStore + this.roomStore = options.roomStore + this.messageBuffer = [] // { message, ready } + } + + connect () { + return new Promise((resolve, reject) => { + this.instance.subscribeNonResuming({ + path: `/rooms/${this.roomId}?${urlEncode({ + message_limit: this.messageLimit + })}`, + listeners: { + onOpen: resolve, + onError: reject, + onEvent: this.onEvent + } + }) + }) + } + + onEvent = ({ body }) => { + switch (body.event_name) { + case 'new_message': + this.onNewMessage(body.data) + break + } + } + + onNewMessage = data => { + const pendingMessage = { + message: new Message( + parseBasicMessage(data), + this.userStore, + this.roomStore + ), + ready: false + } + this.messageBuffer.push(pendingMessage) + this.userStore.fetchMissingUsers([pendingMessage.message.senderId]) + .then(() => { + pendingMessage.ready = true + this.flushBuffer() + }) + } + + flushBuffer = () => { + while (!isEmpty(this.messageBuffer) && head(this.messageBuffer).ready) { + if (this.hooks.newMessage) { + this.hooks.newMessage(this.messageBuffer.shift().message) + } + } + } +} diff --git a/tests/main.js b/tests/main.js index e514690..a23e0e8 100644 --- a/tests/main.js +++ b/tests/main.js @@ -87,33 +87,33 @@ const sendMessages = (user, room, texts) => length(texts) === 0 // Imports -test('can import TokenProvider', t => { +test.skip('can import TokenProvider', t => { t.equal(typeof TokenProvider, 'function') t.end() }) -test('can import ChatManager', t => { +test.skip('can import ChatManager', t => { t.equal(typeof ChatManager, 'function') t.end() }) // Token provider -test('instantiate TokenProvider with url', t => { +test.skip('instantiate TokenProvider with url', t => { const tokenProvider = new TokenProvider({ url: TOKEN_PROVIDER_URL }) t.equal(typeof tokenProvider, 'object') t.equal(typeof tokenProvider.fetchToken, 'function') t.end() }) -test('instantiate TokenProvider with non-string url fails', t => { +test.skip('instantiate TokenProvider with non-string url fails', t => { t.throws(() => new TokenProvider({ url: 42 }), /url/) t.end() }) // Chat manager -test('instantiate ChatManager with correct params', t => { +test.skip('instantiate ChatManager with correct params', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -124,7 +124,7 @@ test('instantiate ChatManager with correct params', t => { t.end() }) -test('instantiate ChatManager with non-string instanceLocator fails', t => { +test.skip('instantiate ChatManager with non-string instanceLocator fails', t => { t.throws(() => new ChatManager({ instanceLocator: 42, userId: 'alice', @@ -133,7 +133,7 @@ test('instantiate ChatManager with non-string instanceLocator fails', t => { t.end() }) -test('instantiate ChatManager without userId fails', t => { +test.skip('instantiate ChatManager without userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -142,7 +142,7 @@ test('instantiate ChatManager without userId fails', t => { t.end() }) -test('instantiate ChatManager with non-string userId fails', t => { +test.skip('instantiate ChatManager with non-string userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -151,7 +151,7 @@ test('instantiate ChatManager with non-string userId fails', t => { t.end() }) -test('instantiate ChatManager with non tokenProvider fails', t => { +test.skip('instantiate ChatManager with non tokenProvider fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -160,7 +160,7 @@ test('instantiate ChatManager with non tokenProvider fails', t => { t.end() }) -test('connection fails if provided with non-function hooks', t => { +test.skip('connection fails if provided with non-function hooks', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -173,7 +173,7 @@ test('connection fails if provided with non-function hooks', t => { t.end() }) -test('connection fails for nonexistent user', t => { +test.skip('connection fails for nonexistent user', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -204,7 +204,7 @@ test('[setup] create Alice', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('connection resolves with current user object', t => { +test.skip('connection resolves with current user object', t => { fetchUser(t, 'alice').then(alice => { t.equal(typeof alice, 'object') t.equal(alice.id, 'alice') @@ -254,7 +254,7 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { // This test has to run before any tests which cause Bob to open a subscription // (since then he will already be online) -test('user came online hook (user sub)', t => { +test.skip('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') @@ -270,7 +270,7 @@ test('user came online hook (user sub)', t => { // TODO cancel methods so that we can do this, and because we should have them // anyway -test('typing indicators (user sub)', t => { +test.skip('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { @@ -293,7 +293,7 @@ test('typing indicators (user sub)', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('user left room hook (user sub) [removes Bob from his own room]', t => { +test.skip('user left room hook (user sub) [removes Bob from his own room]', t => { fetchUser(t, 'alice', { userLeftRoom: (room, user) => { t.equal(room.id, bobsRoom.id) @@ -309,7 +309,7 @@ test('user left room hook (user sub) [removes Bob from his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('user joined room hook (user sub) [Bob rejoins his own room]', t => { +test.skip('user joined room hook (user sub) [Bob rejoins his own room]', t => { fetchUser(t, 'alice', { userJoinedRoom: (room, user) => { t.equal(room.id, bobsRoom.id) @@ -325,7 +325,7 @@ test('user joined room hook (user sub) [Bob rejoins his own room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('room updated hook', t => { +test.skip('room updated hook', t => { fetchUser(t, 'alice', { roomUpdated: room => { t.equal(room.id, bobsRoom.id) @@ -341,7 +341,7 @@ test('room updated hook', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`removed from room hook [removes Alice from Bob's room]`, t => { +test.skip(`removed from room hook [removes Alice from Bob's room]`, t => { fetchUser(t, 'alice', { removedFromRoom: room => { t.equal(room.id, bobsRoom.id) @@ -356,7 +356,7 @@ test(`removed from room hook [removes Alice from Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`room deleted hook [destroys Alice's room]`, t => { +test.skip(`room deleted hook [destroys Alice's room]`, t => { fetchUser(t, 'alice', { roomDeleted: room => { t.equal(room.id, alicesRoom.id) @@ -370,7 +370,7 @@ test(`room deleted hook [destroys Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create room [creates Alice's new room]`, t => { +test.skip(`create room [creates Alice's new room]`, t => { fetchUser(t, 'alice') .then(alice => alice.createRoom({ name: `Alice's new room` })) .then(room => { @@ -385,7 +385,7 @@ test(`create room [creates Alice's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create private room [creates Alice's private room]`, t => { +test.skip(`create private room [creates Alice's private room]`, t => { fetchUser(t, 'alice') .then(alice => alice.createRoom({ name: `Alice's private room`, @@ -403,7 +403,7 @@ test(`create private room [creates Alice's private room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`create room with members [creates Bob's new room]`, t => { +test.skip(`create room with members [creates Bob's new room]`, t => { fetchUser(t, 'bob') .then(bob => bob.createRoom({ name: `Bob's new room`, @@ -421,7 +421,7 @@ test(`create room with members [creates Bob's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('get joined rooms', t => { +test.skip('get joined rooms', t => { const expectedRoomIds = [alicesRoom, bobsRoom, alicesPrivateRoom] .map(r => r.id).sort() fetchUser(t, 'alice') @@ -432,7 +432,7 @@ test('get joined rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('get joinable rooms', t => { +test.skip('get joinable rooms', t => { fetchUser(t, 'bob') .then(bob => bob.getJoinableRooms()) .then(rooms => { @@ -449,7 +449,7 @@ test('get joinable rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('get all rooms', t => { +test.skip('get all rooms', t => { fetchUser(t, 'bob') .then(bob => bob.getAllRooms()) .then(rooms => { @@ -466,7 +466,7 @@ test('get all rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`join room [Bob joins Alice's room]`, t => { +test.skip(`join room [Bob joins Alice's room]`, t => { fetchUser(t, 'bob') .then(bob => bob.joinRoom(alicesRoom.id) .then(room => { @@ -484,7 +484,7 @@ test(`join room [Bob joins Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`leave room [Bob leaves Alice's room]`, t => { +test.skip(`leave room [Bob leaves Alice's room]`, t => { fetchUser(t, 'bob') .then(bob => { t.true( @@ -503,7 +503,7 @@ test(`leave room [Bob leaves Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('add user [Alice adds Bob to her room]', t => { +test.skip('add user [Alice adds Bob to her room]', t => { fetchUser(t, 'alice') .then(alice => alice.addUser('bob', alicesRoom.id) .then(() => { @@ -516,7 +516,7 @@ test('add user [Alice adds Bob to her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('remove user [Alice removes Bob from her room]', t => { +test.skip('remove user [Alice removes Bob from her room]', t => { fetchUser(t, 'alice') .then(alice => alice.removeUser('bob', alicesRoom.id) .then(() => { @@ -539,7 +539,7 @@ test(`send message [sends four messages to Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('fetch messages', t => { +test.skip('fetch messages', t => { fetchUser(t, 'alice') .then(alice => alice.fetchMessages(bobsRoom.id)) .then(messages => { @@ -554,7 +554,7 @@ test('fetch messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('fetch messages with pagination', t => { +test.skip('fetch messages with pagination', t => { fetchUser(t, 'alice') .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 2 }) .then(messages => { @@ -571,12 +571,14 @@ test('fetch messages with pagination', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and fetch initial messages', t => { +test('subscribe to room and fetch initial messages', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( - find(r => r.id === bobsRoom.id, alice.rooms), + bobsRoom.id, { newMessage: concatBatch(4, messages => { t.deepEqual(map(m => m.text, messages), ['hello', 'hey', 'hi', 'ho']) + t.equal(messages[0].sender.name, 'Alice') + t.equal(messages[0].room.name, `Bob's room`) t.end() }) } From 73b44e97e3945451307ef45d41b1e14fc98bebed Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 16:19:06 +0000 Subject: [PATCH 33/99] room subscription --- src/room-subscription.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/room-subscription.js b/src/room-subscription.js index 6b794a2..55880d8 100644 --- a/src/room-subscription.js +++ b/src/room-subscription.js @@ -40,7 +40,7 @@ export class RoomSubscription { } onNewMessage = data => { - const pendingMessage = { + const pending = { message: new Message( parseBasicMessage(data), this.userStore, @@ -48,12 +48,11 @@ export class RoomSubscription { ), ready: false } - this.messageBuffer.push(pendingMessage) - this.userStore.fetchMissingUsers([pendingMessage.message.senderId]) - .then(() => { - pendingMessage.ready = true - this.flushBuffer() - }) + this.messageBuffer.push(pending) + this.userStore.fetchMissingUsers([pending.message.senderId]).then(() => { + pending.ready = true + this.flushBuffer() + }) } flushBuffer = () => { From 2b69b86fee5825c14492871fb6b936cfac3fecaa Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Feb 2018 16:22:52 +0000 Subject: [PATCH 34/99] subscribe to room variations --- tests/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/main.js b/tests/main.js index a23e0e8..61477f4 100644 --- a/tests/main.js +++ b/tests/main.js @@ -586,9 +586,9 @@ test('subscribe to room and fetch initial messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and fetch last two message only', t => { +test('subscribe to room and fetch last two message only', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( - find(r => r.id === bobsRoom.id, alice.rooms), + bobsRoom.id, { newMessage: concatBatch(2, messages => { t.deepEqual(map(m => m.text, messages), ['hi', 'ho']) @@ -600,10 +600,10 @@ test.skip('subscribe to room and fetch last two message only', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and receive sent messages', t => { +test('subscribe to room and receive sent messages', t => { fetchUser(t, 'alice').then(alice => { alice.subscribeToRoom( - find(r => r.id === bobsRoom.id, alice.rooms), + bobsRoom.id, { newMessage: concatBatch(3, messages => { t.deepEqual(map(m => m.text, messages), ['yo', 'yoo', 'yooo']) From 234b66db9b20806cec678135c43ca58be614d8e8 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 11:14:34 +0000 Subject: [PATCH 35/99] userJoined and online/offline hooks on room sub --- src/current-user.js | 9 ++++-- src/presence-subscription.js | 63 +++++++++++++++++++++++++++++++----- src/user-subscription.js | 7 ++++ tests/main.js | 24 +++++++------- 4 files changed, 82 insertions(+), 21 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index fe9d48d..bb81fb1 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -228,6 +228,8 @@ export class CurrentUser { typeCheck('roomId', 'number', roomId) typeCheckObj('hooks', 'function', hooks) messageLimit && typeCheck('messageLimit', 'number', messageLimit) + // TODO what is the desired behaviour if there is already a subscription to + // this room? Close the old one? Throw an error? Merge the hooks? this.roomSubscriptions[roomId] = new RoomSubscription({ roomId, hooks, @@ -255,7 +257,8 @@ export class CurrentUser { instance: this.apiInstance, userStore: this.userStore, roomStore: this.roomStore, - typingIndicators: this.typingIndicators + typingIndicators: this.typingIndicators, + roomSubscriptions: this.roomSubscriptions }) return this.userSubscription.connect().then(({ user, basicRooms }) => { this.avatarURL = user.avatarURL @@ -273,7 +276,9 @@ export class CurrentUser { userId: this.id, instance: this.apiInstance, userStore: this.userStore, - presenceStore: this.presenceStore + roomStore: this.roomStore, + presenceStore: this.presenceStore, + roomSubscriptions: this.roomSubscriptions }) return this.presenceSubscription.connect() } diff --git a/src/presence-subscription.js b/src/presence-subscription.js index ed100b7..b2a938b 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -1,4 +1,13 @@ -import { indexBy, prop, map } from 'ramda' +import { + compose, + contains, + filter, + forEach, + indexBy, + map, + prop, + values +} from 'ramda' import { parsePresenceState } from './parsers' @@ -8,7 +17,9 @@ export class PresenceSubscription { this.hooks = options.hooks this.instance = options.instance this.userStore = options.userStore + this.roomStore = options.roomStore this.presenceStore = options.presenceStore + this.roomSubscriptions = options.roomSubscriptions } connect () { @@ -44,12 +55,48 @@ export class PresenceSubscription { onPresenceUpdate = data => { const presence = parsePresenceState(data) - this.presenceStore.set(presence.userId, presence).then(p => { - if (p.state === 'online' && this.hooks.userCameOnline) { - this.userStore.get(p.userId).then(this.hooks.userCameOnline) - } else if (p.state === 'offline' && this.hooks.userWentOffline) { - this.userStore.get(p.userId).then(this.hooks.userWentOffline) - } - }) + this.presenceStore.set(presence.userId, presence) + .then(p => this.userStore.get(p.userId) + .then(user => { + switch (p.state) { + case 'online': + this.onCameOnline(user) + break + case 'offline': + this.onWentOffline(user) + break + } + }) + ) + } + + onCameOnline = user => { + if (this.hooks.userCameOnline) { + this.hooks.userCameOnline(user) + } + compose( + forEach(sub => this.roomStore.get(sub.roomId).then(room => { + if (contains(user.id, room.userIds)) { + sub.hooks.userCameOnlineInRoom(user) + } + })), + filter(sub => sub.hooks.userCameOnlineInRoom !== undefined), + values + )(this.roomSubscriptions) + } + + onWentOffline = user => { + if (this.hooks.userWentOffline) { + this.hooks.userWentOffline(user) + } + compose( + forEach(sub => this.roomStore.get(sub.roomId).then(room => { + if (contains(user.id, room.userIds)) { + sub.hooks.userWentOfflineInRoom(user) + } + })), + filter(sub => sub.hooks.userWentOfflineInRoom !== undefined), + values + )(this.roomSubscriptions) } } diff --git a/src/user-subscription.js b/src/user-subscription.js index 9c58ea4..b8f7308 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -10,6 +10,7 @@ export class UserSubscription { this.userStore = options.userStore this.roomStore = options.roomStore this.typingIndicators = options.typingIndicators + this.roomSubscriptions = options.roomSubscriptions } connect () { @@ -85,6 +86,12 @@ export class UserSubscription { if (this.hooks.userJoinedRoom) { this.hooks.userJoinedRoom(room, user) } + if ( + this.roomSubscriptions[roomId] && + this.roomSubscriptions[roomId].hooks.userJoined + ) { + this.roomSubscriptions[roomId].hooks.userJoined(user) + } }) }) } diff --git a/tests/main.js b/tests/main.js index 61477f4..26c854c 100644 --- a/tests/main.js +++ b/tests/main.js @@ -270,7 +270,7 @@ test.skip('user came online hook (user sub)', t => { // TODO cancel methods so that we can do this, and because we should have them // anyway -test.skip('typing indicators (user sub)', t => { +test('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { @@ -529,7 +529,7 @@ test.skip('remove user [Alice removes Bob from her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`send message [sends four messages to Bob's room]`, t => { +test.skip(`send message [sends four messages to Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => sendMessages(alice, bobsRoom, [ 'hello', 'hey', 'hi', 'ho' @@ -571,7 +571,7 @@ test.skip('fetch messages with pagination', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and fetch initial messages', t => { +test.skip('subscribe to room and fetch initial messages', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( bobsRoom.id, { @@ -586,7 +586,7 @@ test('subscribe to room and fetch initial messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and fetch last two message only', t => { +test.skip('subscribe to room and fetch last two message only', t => { fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( bobsRoom.id, { @@ -600,7 +600,7 @@ test('subscribe to room and fetch last two message only', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('subscribe to room and receive sent messages', t => { +test.skip('subscribe to room and receive sent messages', t => { fetchUser(t, 'alice').then(alice => { alice.subscribeToRoom( bobsRoom.id, @@ -617,15 +617,15 @@ test('subscribe to room and receive sent messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('[setup] create Carol', t => server.createUser('carol', 'Carol') +test('[setup] create Carol', t => server.createUser('carol', 'Carol') .then(() => t.end()) .catch(endWithErr(t)) ) -test.skip(`user joined hook [Carol joins Bob's room]`, t => { +test(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => { - alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { + alice.subscribeToRoom(bobsRoom.id, { userJoined: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') @@ -639,6 +639,7 @@ test.skip(`user joined hook [Carol joins Bob's room]`, t => { body: { user_ids: ['carol'] }, jwt: server.generateAccessToken({ userId: 'admin', su: true }).token })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -647,7 +648,7 @@ test.skip(`user joined hook [Carol joins Bob's room]`, t => { test.skip('user came online hook', t => { fetchUser(t, 'alice') .then(alice => { - alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { + alice.subscribeToRoom(bobsRoom.id, { // FIXME inconsistent naming userCameOnlineInRoom: once(user => { t.equal(user.id, 'carol') @@ -659,13 +660,14 @@ test.skip('user came online hook', t => { // FIXME We have to wrap this in a timeout to give the presence // subscription a chance to finish. Not ideal. .then(() => setTimeout(() => fetchUser(t, 'carol'), 1000)) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. -test.skip('typing indicators', t => { +test('typing indicators', t => { let started Promise.all([ fetchUser(t, 'alice').then(alice => { @@ -747,7 +749,7 @@ test.skip('non-admin delete room fails gracefully', t => { // TODO read cursors (perhaps reconsider interface) -test.skip('[teardown] destroy Carol', t => { +test('[teardown] destroy Carol', t => { server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) t.timeoutAfter(TEST_TIMEOUT) }) From 7133cf0f51274bfcb204adda472bf95b290ad5a6 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 13:53:11 +0000 Subject: [PATCH 36/99] room level typing indicators --- src/typing-indicators.js | 28 ++++++++++++++++++----- src/user-subscription.js | 13 +++++++---- tests/main.js | 48 +++++++++++++++++----------------------- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/typing-indicators.js b/src/typing-indicators.js index 52d90d6..e05014c 100644 --- a/src/typing-indicators.js +++ b/src/typing-indicators.js @@ -35,20 +35,36 @@ export class TypingIndicators { }) } - onIsTyping = (room, user, hooks) => { + onIsTyping = (room, user, hooks, roomHooks) => { if (!this.timers[room.id]) { this.timers[room.id] = {} } if (this.timers[room.id][user.id]) { clearTimeout(this.timers[room.id][user.id]) - } else if (hooks.userStartedTyping) { - hooks.userStartedTyping(room, user) + } else { + this.onStarted(room, user, hooks, roomHooks) } this.timers[room.id][user.id] = setTimeout(() => { - if (hooks.userStoppedTyping) { - hooks.userStoppedTyping(room, user) - } + this.onStopped(room, user, hooks, roomHooks) delete this.timers[room.id][user.id] }, TYPING_INDICATOR_TTL) } + + onStarted = (room, user, hooks, roomHooks) => { + if (hooks.userStartedTyping) { + hooks.userStartedTyping(room, user) + } + if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { + roomHooks[room.id].userStartedTyping(user) + } + } + + onStopped = (room, user, hooks, roomHooks) => { + if (hooks.userStoppedTyping) { + hooks.userStoppedTyping(room, user) + } + if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { + roomHooks[room.id].userStoppedTyping(user) + } + } } diff --git a/src/user-subscription.js b/src/user-subscription.js index b8f7308..94e7a97 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -1,4 +1,4 @@ -import { map } from 'ramda' +import { map, prop } from 'ramda' import { parseBasicRoom, parseUser } from './parsers' @@ -50,7 +50,7 @@ export class UserSubscription { this.onRoomDeleted(body.data) break case 'typing_start': // TODO 'is_typing' - this.onTypingStart(body.data) + this.onIsTyping(body.data) break } } @@ -123,8 +123,13 @@ export class UserSubscription { }) } - onTypingStart = ({ room_id: roomId, user_id: userId }) => { + onIsTyping = ({ room_id: roomId, user_id: userId }) => { Promise.all([this.roomStore.get(roomId), this.userStore.get(userId)]) - .then(([r, u]) => this.typingIndicators.onIsTyping(r, u, this.hooks)) + .then(([room, user]) => this.typingIndicators.onIsTyping( + room, + user, + this.hooks, + map(prop('hooks'), this.roomSubscriptions) + )) } } diff --git a/tests/main.js b/tests/main.js index 26c854c..3c3a779 100644 --- a/tests/main.js +++ b/tests/main.js @@ -624,15 +624,13 @@ test('[setup] create Carol', t => server.createUser('carol', 'Carol') test(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') - .then(alice => { - alice.subscribeToRoom(bobsRoom.id, { - userJoined: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.end() - }) + .then(alice => alice.subscribeToRoom(bobsRoom.id, { + userJoined: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.end() }) - }) + })) .then(() => server.apiRequest({ method: 'PUT', path: `/rooms/${bobsRoom.id}/users/add`, @@ -645,21 +643,17 @@ test(`user joined hook [Carol joins Bob's room]`, t => { // This test has to run before any tests which cause Carol to open a // subscription (since then she will already be online) -test.skip('user came online hook', t => { +test('user came online hook', t => { fetchUser(t, 'alice') - .then(alice => { - alice.subscribeToRoom(bobsRoom.id, { - // FIXME inconsistent naming - userCameOnlineInRoom: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.end() - }) + .then(alice => alice.subscribeToRoom(bobsRoom.id, { + // FIXME inconsistent naming + userCameOnlineInRoom: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.end() }) - }) - // FIXME We have to wrap this in a timeout to give the presence - // subscription a chance to finish. Not ideal. - .then(() => setTimeout(() => fetchUser(t, 'carol'), 1000)) + })) + .then(() => fetchUser(t, 'carol')) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -670,8 +664,8 @@ test.skip('user came online hook', t => { test('typing indicators', t => { let started Promise.all([ - fetchUser(t, 'alice').then(alice => { - alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(bobsRoom.id, { userStartedTyping: once(user => { started = Date.now() t.equal(user.id, 'carol') @@ -683,14 +677,12 @@ test('typing indicators', t => { t.true(Date.now() - started > 1000, 'fired more than 1s after start') t.end() }) - }) - return alice - }), + })), fetchUser(t, 'carol') - ]).then(([alice, carol]) => carol.isTypingIn( + ]).then(([x, carol]) => carol.isTypingIn( bobsRoom.id, () => {}, - err => t.end(err) + endWithErr(t) )) t.timeoutAfter(TEST_TIMEOUT) }) From c93f6b013f7bb484760dc466513a96fb7a5cf5fa Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 13:55:57 +0000 Subject: [PATCH 37/99] room level user left --- src/user-subscription.js | 6 ++++++ tests/main.js | 16 +++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/user-subscription.js b/src/user-subscription.js index 94e7a97..f3a1543 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -102,6 +102,12 @@ export class UserSubscription { if (this.hooks.userLeftRoom) { this.hooks.userLeftRoom(room, user) } + if ( + this.roomSubscriptions[roomId] && + this.roomSubscriptions[roomId].hooks.userLeft + ) { + this.roomSubscriptions[roomId].hooks.userLeft(user) + } }) }) } diff --git a/tests/main.js b/tests/main.js index 3c3a779..9f33603 100644 --- a/tests/main.js +++ b/tests/main.js @@ -687,17 +687,15 @@ test('typing indicators', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`user left hook [removes Carol from Bob's room]`, t => { +test(`user left hook [removes Carol from Bob's room]`, t => { fetchUser(t, 'alice') - .then(alice => { - alice.subscribeToRoom(find(r => r.id === bobsRoom.id, alice.rooms), { - userLeft: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.end() - }) + .then(alice => alice.subscribeToRoom(bobsRoom.id, { + userLeft: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.end() }) - }) + })) .then(() => server.apiRequest({ method: 'PUT', path: `/rooms/${bobsRoom.id}/users/remove`, From 4aad1d46a30143ae455cdd305e802dde0680639a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 15:31:25 +0000 Subject: [PATCH 38/99] avoid looping forever if no newMessage callback set... -_- all tests passing (that were passing before) --- package.json | 1 - src/current-user.js | 3 +- src/room-store.js | 22 ++-- src/room-subscription.js | 15 ++- src/user-store.js | 21 ++- tests/main.js | 274 ++++++++++++++++++++++----------------- yarn.lock | 27 ---- 7 files changed, 196 insertions(+), 167 deletions(-) diff --git a/package.json b/package.json index 2266c55..01b3e43 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "snazzy": "^7.0.0", "standard": "^10.0.3", "tape": "^4.8.0", - "tape-catch": "^1.0.6", "tape-run": "^3.0.2" }, "scripts": { diff --git a/src/current-user.js b/src/current-user.js index bb81fb1..a863232 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -237,7 +237,8 @@ export class CurrentUser { userId: this.id, instance: this.apiInstance, userStore: this.userStore, - roomStore: this.roomStore + roomStore: this.roomStore, + logger: this.logger }) return this.roomSubscriptions[roomId].connect() } diff --git a/src/room-store.js b/src/room-store.js index 897a881..82ff2e2 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -1,4 +1,4 @@ -import { append, map, mergeWith, filter, uniq } from 'ramda' +import { append, map, mergeWith, filter, uniq, curry, pipe } from 'ramda' import { Store } from './store' import { parseBasicRoom } from './parsers' @@ -15,25 +15,27 @@ export class RoomStore { initialize = this.store.initialize - set = (roomId, basicRoom) => { + set = curry((roomId, basicRoom) => { return this.store.set(roomId, basicRoom) .then(this.decorate) .then(room => this.userStore.fetchMissingUsers(room.userIds).then(() => room) ) - } + }) get = roomId => this.store.get(roomId).then(basicRoom => - basicRoom || this.fetchBasicRoom(roomId) + basicRoom || this.fetchBasicRoom(roomId).then(this.set(roomId)) ).then(this.decorate) - pop = roomId => this.store.pop(roomId).then(this.decorate) + pop = roomId => this.store.pop(roomId).then(basicRoom => + basicRoom || this.fetchBasicRoom(roomId) + ).then(this.decorate) - addUserToRoom = (roomId, userId) => this.store.pop(roomId).then(r => + addUserToRoom = (roomId, userId) => this.pop(roomId).then(r => this.set(roomId, { ...r, userIds: uniq(append(userId, r.userIds)) }) ) - removeUserFromRoom = (roomId, userId) => this.store.pop(roomId).then(r => + removeUserFromRoom = (roomId, userId) => this.pop(roomId).then(r => this.set(roomId, { ...r, userIds: filter(id => id !== userId, r.userIds) }) ) @@ -47,11 +49,7 @@ export class RoomStore { method: 'GET', path: `/rooms/${roomId}` }) - .then(res => { - const basicRoom = parseBasicRoom(JSON.parse(res)) - this.set(roomId, basicRoom) - return basicRoom - }) + .then(pipe(JSON.parse, parseBasicRoom)) .catch(err => { this.logger.warn('error fetching room information:', err) throw err diff --git a/src/room-subscription.js b/src/room-subscription.js index 55880d8..d77343a 100644 --- a/src/room-subscription.js +++ b/src/room-subscription.js @@ -49,16 +49,21 @@ export class RoomSubscription { ready: false } this.messageBuffer.push(pending) - this.userStore.fetchMissingUsers([pending.message.senderId]).then(() => { - pending.ready = true - this.flushBuffer() - }) + this.userStore.fetchMissingUsers([pending.message.senderId]) + .catch(err => { + this.logger.error('error fetching missing user information:', err) + }) + .then(() => { + pending.ready = true + this.flushBuffer() + }) } flushBuffer = () => { while (!isEmpty(this.messageBuffer) && head(this.messageBuffer).ready) { + const message = this.messageBuffer.shift().message if (this.hooks.newMessage) { - this.hooks.newMessage(this.messageBuffer.shift().message) + this.hooks.newMessage(message) } } } diff --git a/src/user-store.js b/src/user-store.js index c1e01d5..f4ab57b 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -1,4 +1,13 @@ -import { difference, join, length, map, pipe, prop, forEach } from 'ramda' +import { + difference, + forEach, + join, + length, + map, + pipe, + prop, + values +} from 'ramda' import { appendQueryParam } from './utils' import { Store } from './store' @@ -18,11 +27,11 @@ export class UserStore { set = this.store.set get = userId => Promise.all([ - this.store.get(userId).then(user => user || this.fetchUser(userId)), + this.store.get(userId).then(user => user || this.fetchBasicUser(userId)), this.presenceStore.get(userId) ]).then(([user, presence]) => ({ ...user, presence })) - fetchUser = userId => { + fetchBasicUser = userId => { return this.instance .request({ method: 'GET', @@ -40,10 +49,14 @@ export class UserStore { } fetchMissingUsers = userIds => { - const missing = difference(userIds, map(prop('id'), this.store.snapshot())) + const missing = difference( + userIds, + map(prop('id'), values(this.store.snapshot())) + ) if (length(missing) === 0) { return Promise.resolve() } + // TODO don't make simulatneous requests for the same users return this.instance .request({ method: 'GET', diff --git a/tests/main.js b/tests/main.js index 9f33603..5613ef4 100644 --- a/tests/main.js +++ b/tests/main.js @@ -1,4 +1,4 @@ -import test from 'tape-catch' +import test from 'tape' import { any, compose, @@ -85,35 +85,50 @@ const sendMessages = (user, room, texts) => length(texts) === 0 : user.sendMessage({ roomId: room.id, text: head(texts) }) .then(() => sendMessages(user, room, tail(texts))) +test('[teardown] destroy Carol', t => { + server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('[teardown] destroy Bob', t => { + server.deleteUser('bob').then(() => t.end()).catch(err => t.end(err)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('[teardown] destroy Alice', t => { + server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) + t.timeoutAfter(TEST_TIMEOUT) +}) + // Imports -test.skip('can import TokenProvider', t => { +test('can import TokenProvider', t => { t.equal(typeof TokenProvider, 'function') t.end() }) -test.skip('can import ChatManager', t => { +test('can import ChatManager', t => { t.equal(typeof ChatManager, 'function') t.end() }) // Token provider -test.skip('instantiate TokenProvider with url', t => { +test('instantiate TokenProvider with url', t => { const tokenProvider = new TokenProvider({ url: TOKEN_PROVIDER_URL }) t.equal(typeof tokenProvider, 'object') t.equal(typeof tokenProvider.fetchToken, 'function') t.end() }) -test.skip('instantiate TokenProvider with non-string url fails', t => { +test('instantiate TokenProvider with non-string url fails', t => { t.throws(() => new TokenProvider({ url: 42 }), /url/) t.end() }) // Chat manager -test.skip('instantiate ChatManager with correct params', t => { +test('instantiate ChatManager with correct params', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -124,7 +139,7 @@ test.skip('instantiate ChatManager with correct params', t => { t.end() }) -test.skip('instantiate ChatManager with non-string instanceLocator fails', t => { +test('instantiate ChatManager with non-string instanceLocator fails', t => { t.throws(() => new ChatManager({ instanceLocator: 42, userId: 'alice', @@ -133,7 +148,7 @@ test.skip('instantiate ChatManager with non-string instanceLocator fails', t => t.end() }) -test.skip('instantiate ChatManager without userId fails', t => { +test('instantiate ChatManager without userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -142,7 +157,7 @@ test.skip('instantiate ChatManager without userId fails', t => { t.end() }) -test.skip('instantiate ChatManager with non-string userId fails', t => { +test('instantiate ChatManager with non-string userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -151,7 +166,7 @@ test.skip('instantiate ChatManager with non-string userId fails', t => { t.end() }) -test.skip('instantiate ChatManager with non tokenProvider fails', t => { +test('instantiate ChatManager with non tokenProvider fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, @@ -160,7 +175,7 @@ test.skip('instantiate ChatManager with non tokenProvider fails', t => { t.end() }) -test.skip('connection fails if provided with non-function hooks', t => { +test('connection fails if provided with non-function hooks', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -173,7 +188,7 @@ test.skip('connection fails if provided with non-function hooks', t => { t.end() }) -test.skip('connection fails for nonexistent user', t => { +test('connection fails for nonexistent user', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', @@ -204,22 +219,24 @@ test('[setup] create Alice', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('connection resolves with current user object', t => { - fetchUser(t, 'alice').then(alice => { - t.equal(typeof alice, 'object') - t.equal(alice.id, 'alice') - t.equal(alice.name, 'Alice') - t.true(Array.isArray(alice.rooms), 'alice.rooms is an array') - t.equal(length(alice.rooms), 1) - t.equal(alice.rooms[0].name, `Alice's room`) - t.equal(alice.rooms[0].isPrivate, false) - t.equal(alice.rooms[0].createdByUserId, 'alice') - t.deepEqual(alice.rooms[0].userIds, ['alice']) - t.true(Array.isArray(alice.rooms[0].users), 'users is an array') - t.equal(length(alice.rooms[0].users), 1) - t.equal(alice.rooms[0].users[0].name, 'Alice') - t.end() - }) +test('connection resolves with current user object', t => { + fetchUser(t, 'alice') + .then(alice => { + t.equal(typeof alice, 'object') + t.equal(alice.id, 'alice') + t.equal(alice.name, 'Alice') + t.true(Array.isArray(alice.rooms), 'alice.rooms is an array') + t.equal(length(alice.rooms), 1) + t.equal(alice.rooms[0].name, `Alice's room`) + t.equal(alice.rooms[0].isPrivate, false) + t.equal(alice.rooms[0].createdByUserId, 'alice') + t.deepEqual(alice.rooms[0].userIds, ['alice']) + t.true(Array.isArray(alice.rooms[0].users), 'users is an array') + t.equal(length(alice.rooms[0].users), 1) + t.equal(alice.rooms[0].users[0].name, 'Alice') + t.end() + }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -249,19 +266,22 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { .then(room => { bobsRoom = room // we'll want this in the following tests }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) // This test has to run before any tests which cause Bob to open a subscription // (since then he will already be online) -test.skip('user came online hook (user sub)', t => { +test('user came online hook (user sub)', t => { fetchUser(t, 'alice', { userCameOnline: user => { t.equal(user.id, 'bob') t.equal(user.presence.state, 'online') t.end() } - }).then(() => fetchUser(t, 'bob')) + }) + .then(() => fetchUser(t, 'bob')) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -293,84 +313,94 @@ test('typing indicators (user sub)', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('user left room hook (user sub) [removes Bob from his own room]', t => { +test('user left room hook (user sub) [removes Bob from his own room]', t => { fetchUser(t, 'alice', { userLeftRoom: (room, user) => { t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') t.end() } - }).then(() => server.apiRequest({ - method: 'PUT', - path: `/rooms/${bobsRoom.id}/users/remove`, - body: { user_ids: ['bob'] }, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) + }) + .then(() => server.apiRequest({ + method: 'PUT', + path: `/rooms/${bobsRoom.id}/users/remove`, + body: { user_ids: ['bob'] }, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('user joined room hook (user sub) [Bob rejoins his own room]', t => { +test('user joined room hook (user sub) [Bob rejoins his own room]', t => { fetchUser(t, 'alice', { userJoinedRoom: (room, user) => { t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') t.end() } - }).then(() => server.apiRequest({ - method: 'PUT', - path: `/rooms/${bobsRoom.id}/users/add`, - body: { user_ids: ['bob'] }, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) + }) + .then(() => server.apiRequest({ + method: 'PUT', + path: `/rooms/${bobsRoom.id}/users/add`, + body: { user_ids: ['bob'] }, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('room updated hook', t => { +test('room updated hook', t => { fetchUser(t, 'alice', { roomUpdated: room => { t.equal(room.id, bobsRoom.id) t.equal(room.name, `Bob's renamed room`) t.end() } - }).then(() => server.apiRequest({ - method: 'PUT', - path: `/rooms/${bobsRoom.id}`, - body: { name: `Bob's renamed room` }, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) + }) + .then(() => server.apiRequest({ + method: 'PUT', + path: `/rooms/${bobsRoom.id}`, + body: { name: `Bob's renamed room` }, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`removed from room hook [removes Alice from Bob's room]`, t => { +test(`removed from room hook [removes Alice from Bob's room]`, t => { fetchUser(t, 'alice', { removedFromRoom: room => { t.equal(room.id, bobsRoom.id) t.end() } - }).then(() => server.apiRequest({ - method: 'PUT', - path: `/rooms/${bobsRoom.id}/users/remove`, - body: { user_ids: ['alice'] }, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) + }) + .then(() => server.apiRequest({ + method: 'PUT', + path: `/rooms/${bobsRoom.id}/users/remove`, + body: { user_ids: ['alice'] }, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`room deleted hook [destroys Alice's room]`, t => { +test(`room deleted hook [destroys Alice's room]`, t => { fetchUser(t, 'alice', { roomDeleted: room => { t.equal(room.id, alicesRoom.id) t.end() } - }).then(() => server.apiRequest({ - method: 'DELETE', - path: `/rooms/${alicesRoom.id}`, - jwt: server.generateAccessToken({ userId: 'admin', su: true }).token - })) + }) + .then(() => server.apiRequest({ + method: 'DELETE', + path: `/rooms/${alicesRoom.id}`, + jwt: server.generateAccessToken({ userId: 'admin', su: true }).token + })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create room [creates Alice's new room]`, t => { +test(`create room [creates Alice's new room]`, t => { fetchUser(t, 'alice') .then(alice => alice.createRoom({ name: `Alice's new room` })) .then(room => { @@ -385,7 +415,7 @@ test.skip(`create room [creates Alice's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create private room [creates Alice's private room]`, t => { +test(`create private room [creates Alice's private room]`, t => { fetchUser(t, 'alice') .then(alice => alice.createRoom({ name: `Alice's private room`, @@ -403,7 +433,7 @@ test.skip(`create private room [creates Alice's private room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`create room with members [creates Bob's new room]`, t => { +test(`create room with members [creates Bob's new room]`, t => { fetchUser(t, 'bob') .then(bob => bob.createRoom({ name: `Bob's new room`, @@ -421,7 +451,7 @@ test.skip(`create room with members [creates Bob's new room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('get joined rooms', t => { +test('get joined rooms', t => { const expectedRoomIds = [alicesRoom, bobsRoom, alicesPrivateRoom] .map(r => r.id).sort() fetchUser(t, 'alice') @@ -429,10 +459,11 @@ test.skip('get joined rooms', t => { t.deepEqual(map(r => r.id, alice.rooms).sort(), expectedRoomIds) t.end() }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('get joinable rooms', t => { +test('get joinable rooms', t => { fetchUser(t, 'bob') .then(bob => bob.getJoinableRooms()) .then(rooms => { @@ -449,7 +480,7 @@ test.skip('get joinable rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('get all rooms', t => { +test('get all rooms', t => { fetchUser(t, 'bob') .then(bob => bob.getAllRooms()) .then(rooms => { @@ -466,7 +497,7 @@ test.skip('get all rooms', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`join room [Bob joins Alice's room]`, t => { +test(`join room [Bob joins Alice's room]`, t => { fetchUser(t, 'bob') .then(bob => bob.joinRoom(alicesRoom.id) .then(room => { @@ -484,7 +515,7 @@ test.skip(`join room [Bob joins Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`leave room [Bob leaves Alice's room]`, t => { +test(`leave room [Bob leaves Alice's room]`, t => { fetchUser(t, 'bob') .then(bob => { t.true( @@ -500,10 +531,11 @@ test.skip(`leave room [Bob leaves Alice's room]`, t => { t.end() }) }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('add user [Alice adds Bob to her room]', t => { +test('add user [Alice adds Bob to her room]', t => { fetchUser(t, 'alice') .then(alice => alice.addUser('bob', alicesRoom.id) .then(() => { @@ -516,7 +548,7 @@ test.skip('add user [Alice adds Bob to her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('remove user [Alice removes Bob from her room]', t => { +test('remove user [Alice removes Bob from her room]', t => { fetchUser(t, 'alice') .then(alice => alice.removeUser('bob', alicesRoom.id) .then(() => { @@ -529,7 +561,7 @@ test.skip('remove user [Alice removes Bob from her room]', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip(`send message [sends four messages to Bob's room]`, t => { +test(`send messages [sends four messages to Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => sendMessages(alice, bobsRoom, [ 'hello', 'hey', 'hi', 'ho' @@ -539,7 +571,7 @@ test.skip(`send message [sends four messages to Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('fetch messages', t => { +test('fetch messages', t => { fetchUser(t, 'alice') .then(alice => alice.fetchMessages(bobsRoom.id)) .then(messages => { @@ -554,7 +586,7 @@ test.skip('fetch messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('fetch messages with pagination', t => { +test('fetch messages with pagination', t => { fetchUser(t, 'alice') .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 2 }) .then(messages => { @@ -571,56 +603,61 @@ test.skip('fetch messages with pagination', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and fetch initial messages', t => { - fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( - bobsRoom.id, - { - newMessage: concatBatch(4, messages => { - t.deepEqual(map(m => m.text, messages), ['hello', 'hey', 'hi', 'ho']) - t.equal(messages[0].sender.name, 'Alice') - t.equal(messages[0].room.name, `Bob's room`) - t.end() - }) - } - )) +test('subscribe to room and fetch initial messages', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom( + bobsRoom.id, + { + newMessage: concatBatch(4, messages => { + t.deepEqual(map(m => m.text, messages), ['hello', 'hey', 'hi', 'ho']) + t.equal(messages[0].sender.name, 'Alice') + t.equal(messages[0].room.name, `Bob's new room`) + t.end() + }) + } + )) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and fetch last two message only', t => { - fetchUser(t, 'alice').then(alice => alice.subscribeToRoom( - bobsRoom.id, - { - newMessage: concatBatch(2, messages => { - t.deepEqual(map(m => m.text, messages), ['hi', 'ho']) - t.end() - }) - }, - 2 - )) +test('subscribe to room and fetch last two message only', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom( + bobsRoom.id, + { + newMessage: concatBatch(2, messages => { + t.deepEqual(map(m => m.text, messages), ['hi', 'ho']) + t.end() + }) + }, + 2 + )) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test.skip('subscribe to room and receive sent messages', t => { - fetchUser(t, 'alice').then(alice => { - alice.subscribeToRoom( - bobsRoom.id, +test('subscribe to room and receive sent messages', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(bobsRoom.id, { newMessage: concatBatch(3, messages => { t.deepEqual(map(m => m.text, messages), ['yo', 'yoo', 'yooo']) + t.equal(messages[0].sender.name, 'Alice') + t.equal(messages[0].room.name, `Bob's new room`) t.end() }) - }, - 0 + }, 0).then(() => sendMessages(alice, bobsRoom, ['yo', 'yoo', 'yooo'])) ) - setTimeout(() => sendMessages(alice, bobsRoom, ['yo', 'yoo', 'yooo']), 1000) - }) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test('[setup] create Carol', t => server.createUser('carol', 'Carol') - .then(() => t.end()) - .catch(endWithErr(t)) -) +test('[setup] create Carol', t => { + server.createUser('carol', 'Carol') + .then(() => t.end()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) test(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') @@ -679,11 +716,13 @@ test('typing indicators', t => { }) })), fetchUser(t, 'carol') - ]).then(([x, carol]) => carol.isTypingIn( - bobsRoom.id, - () => {}, - endWithErr(t) - )) + ]) + .then(([x, carol]) => carol.isTypingIn( + bobsRoom.id, + () => {}, + endWithErr(t) + )) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -702,6 +741,7 @@ test(`user left hook [removes Carol from Bob's room]`, t => { body: { user_ids: ['carol'] }, jwt: server.generateAccessToken({ userId: 'admin', su: true }).token })) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) diff --git a/yarn.lock b/yarn.lock index 92b03f0..34620ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1425,10 +1425,6 @@ doctrine@^2.0.0: dependencies: esutils "^2.0.2" -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - domain-browser@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2082,13 +2078,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2, glob@~7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -global@~4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - globals@^9.14.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2844,12 +2833,6 @@ mime@^1.2.11, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -3314,10 +3297,6 @@ process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - progress-stream@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" @@ -4120,12 +4099,6 @@ tap-parser@~0.4.0: inherits "~2.0.1" readable-stream "~1.1.11" -tape-catch@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/tape-catch/-/tape-catch-1.0.6.tgz#12931d5ea60a03a97d9bd19d0d7d8cfc3f6cecf1" - dependencies: - global "~4.3.0" - tape-run@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/tape-run/-/tape-run-3.0.2.tgz#fbad4b77b72bab77c36e5f1c3610bfa17402c46d" From 076c0eac186a6a85dce77429b4f3fea49cc7963e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 16:19:03 +0000 Subject: [PATCH 39/99] join room presence update --- src/parsers.js | 2 +- src/presence-subscription.js | 14 +++++++++++--- src/room-store.js | 3 +-- tests/main.js | 32 ++++---------------------------- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/parsers.js b/src/parsers.js index 14e217f..9812179 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -20,7 +20,7 @@ export const parseUser = data => ({ updatedAt: data.updated_at }) -export const parsePresenceState = data => ({ +export const parsePresence = data => ({ lastSeenAt: data.last_seen_at, state: contains(data.state, ['online', 'offline']) ? data.state : 'unknown', userId: data.user_id diff --git a/src/presence-subscription.js b/src/presence-subscription.js index b2a938b..970556a 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -9,7 +9,7 @@ import { values } from 'ramda' -import { parsePresenceState } from './parsers' +import { parsePresence } from './parsers' export class PresenceSubscription { constructor (options) { @@ -43,18 +43,21 @@ export class PresenceSubscription { case 'presence_update': this.onPresenceUpdate(body.data) break + case 'join_room_presence_update': + this.onJoinRoomPresenceUpdate(body.data) + break } } onInitialState = ({ user_states: userStates }) => { this.presenceStore.initialize( - indexBy(prop('userId'), map(parsePresenceState, userStates)) + indexBy(prop('userId'), map(parsePresence, userStates)) ) this.hooks.subscriptionEstablished() } onPresenceUpdate = data => { - const presence = parsePresenceState(data) + const presence = parsePresence(data) this.presenceStore.set(presence.userId, presence) .then(p => this.userStore.get(p.userId) .then(user => { @@ -70,6 +73,11 @@ export class PresenceSubscription { ) } + onJoinRoomPresenceUpdate = ({ user_states: userStates }) => forEach( + presence => this.presenceStore.set(presence.userId, presence), + map(parsePresence, userStates) + ) + onCameOnline = user => { if (this.hooks.userCameOnline) { this.hooks.userCameOnline(user) diff --git a/src/room-store.js b/src/room-store.js index 82ff2e2..c5bf613 100644 --- a/src/room-store.js +++ b/src/room-store.js @@ -51,8 +51,7 @@ export class RoomStore { }) .then(pipe(JSON.parse, parseBasicRoom)) .catch(err => { - this.logger.warn('error fetching room information:', err) - throw err + this.logger.warn(`error fetching details for room ${roomId}:`, err) }) } diff --git a/tests/main.js b/tests/main.js index 5613ef4..c53754c 100644 --- a/tests/main.js +++ b/tests/main.js @@ -19,15 +19,6 @@ import ChatkitServer from 'pusher-chatkit-server' import { TokenProvider, ChatManager } from '../dist/web/chatkit.js' import { INSTANCE_LOCATOR, INSTANCE_KEY, TOKEN_PROVIDER_URL } from './config' -// Skipped tests don't currently pass, but should! The tests interact with a -// real instance, and rely on the state of that instance. If the instance gets -// in to an invalid state, you can usually get away with just running the tests -// a couple of times to give the teardown tests a chance to run. -// -// Some tests demonstrate behaviour that is not quite what I think it should -// be, but is close enough to be useful. Specific discrepencies in this case -// are marked with FIXMEs. - let alicesRoom, bobsRoom, alicesPrivateRoom const TEST_TIMEOUT = 15 * 1000 @@ -85,8 +76,8 @@ const sendMessages = (user, room, texts) => length(texts) === 0 : user.sendMessage({ roomId: room.id, text: head(texts) }) .then(() => sendMessages(user, room, tail(texts))) -test('[teardown] destroy Carol', t => { - server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) +test('[teardown] destroy Alice', t => { + server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -95,8 +86,8 @@ test('[teardown] destroy Bob', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test('[teardown] destroy Alice', t => { - server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) +test('[teardown] destroy Carol', t => { + server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -778,18 +769,3 @@ test.skip('non-admin delete room fails gracefully', t => { // TODO files stuff // TODO read cursors (perhaps reconsider interface) - -test('[teardown] destroy Carol', t => { - server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) - t.timeoutAfter(TEST_TIMEOUT) -}) - -test('[teardown] destroy Bob', t => { - server.deleteUser('bob').then(() => t.end()).catch(err => t.end(err)) - t.timeoutAfter(TEST_TIMEOUT) -}) - -test('[teardown] destroy Alice', t => { - server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) - t.timeoutAfter(TEST_TIMEOUT) -}) From b346530db39bdc7dc1e06b18d3195e0444760614 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 16:36:47 +0000 Subject: [PATCH 40/99] dist --- dist/react-native/chatkit.js | 4015 ++++++++++ .../react-native/declarations/attachment.d.ts | 6 + .../declarations/basic_cursor.d.ts | 8 + .../declarations/basic_message.d.ts | 11 + .../declarations/basic_message_enricher.d.ts | 38 + .../react-native/declarations/basic_user.d.ts | 6 + .../declarations/chat_manager.d.ts | 25 + .../declarations/chat_manager_delegate.d.ts | 16 + dist/react-native/declarations/constants.d.ts | 2 + .../declarations/current_user.d.ts | 111 + dist/react-native/declarations/cursor.d.ts | 10 + .../declarations/cursor_subscription.d.ts | 23 + .../declarations/cursor_types.d.ts | 4 + .../declarations/fetched_attachment.d.ts | 11 + .../declarations/global_user_store.d.ts | 22 + dist/react-native/declarations/index.d.ts | 10 + dist/react-native/declarations/message.d.ts | 13 + .../declarations/payload_deserializer.d.ts | 22 + .../declarations/presence_payload.d.ts | 7 + .../declarations/presence_state.d.ts | 4 + .../declarations/presence_subscription.d.ts | 22 + dist/react-native/declarations/room.d.ts | 28 + .../declarations/room_delegate.d.ts | 16 + .../react-native/declarations/room_store.d.ts | 16 + .../declarations/room_subscription.d.ts | 15 + .../declarations/room_user_store.d.ts | 8 + .../declarations/token_provider.d.ts | 29 + dist/react-native/declarations/user.d.ts | 23 + .../declarations/user_store_core.d.ts | 8 + .../declarations/user_subscription.d.ts | 38 + dist/react-native/declarations/utils.d.ts | 5 + dist/web/chatkit.js | 6697 +++++++++++++++++ dist/web/declarations/attachment.d.ts | 6 + dist/web/declarations/basic_cursor.d.ts | 8 + dist/web/declarations/basic_message.d.ts | 11 + .../declarations/basic_message_enricher.d.ts | 38 + dist/web/declarations/basic_user.d.ts | 6 + dist/web/declarations/chat_manager.d.ts | 25 + .../declarations/chat_manager_delegate.d.ts | 16 + dist/web/declarations/constants.d.ts | 2 + dist/web/declarations/current_user.d.ts | 111 + dist/web/declarations/cursor.d.ts | 10 + .../web/declarations/cursor_subscription.d.ts | 23 + dist/web/declarations/cursor_types.d.ts | 4 + dist/web/declarations/fetched_attachment.d.ts | 11 + dist/web/declarations/global_user_store.d.ts | 22 + dist/web/declarations/index.d.ts | 10 + dist/web/declarations/message.d.ts | 13 + .../declarations/payload_deserializer.d.ts | 22 + dist/web/declarations/presence_payload.d.ts | 7 + dist/web/declarations/presence_state.d.ts | 4 + .../declarations/presence_subscription.d.ts | 22 + dist/web/declarations/room.d.ts | 28 + dist/web/declarations/room_delegate.d.ts | 16 + dist/web/declarations/room_store.d.ts | 16 + dist/web/declarations/room_subscription.d.ts | 15 + dist/web/declarations/room_user_store.d.ts | 8 + dist/web/declarations/token_provider.d.ts | 29 + dist/web/declarations/user.d.ts | 23 + dist/web/declarations/user_store_core.d.ts | 8 + dist/web/declarations/user_subscription.d.ts | 38 + dist/web/declarations/utils.d.ts | 5 + dist/worker/chatkit.worker.js | 3982 ++++++++++ dist/worker/declarations/attachment.d.ts | 6 + dist/worker/declarations/basic_cursor.d.ts | 8 + dist/worker/declarations/basic_message.d.ts | 11 + .../declarations/basic_message_enricher.d.ts | 38 + dist/worker/declarations/basic_user.d.ts | 6 + dist/worker/declarations/chat_manager.d.ts | 25 + .../declarations/chat_manager_delegate.d.ts | 16 + dist/worker/declarations/constants.d.ts | 2 + dist/worker/declarations/current_user.d.ts | 111 + dist/worker/declarations/cursor.d.ts | 10 + .../declarations/cursor_subscription.d.ts | 23 + dist/worker/declarations/cursor_types.d.ts | 4 + .../declarations/fetched_attachment.d.ts | 11 + .../declarations/global_user_store.d.ts | 22 + dist/worker/declarations/index.d.ts | 10 + dist/worker/declarations/message.d.ts | 13 + .../declarations/payload_deserializer.d.ts | 22 + .../worker/declarations/presence_payload.d.ts | 7 + dist/worker/declarations/presence_state.d.ts | 4 + .../declarations/presence_subscription.d.ts | 22 + dist/worker/declarations/room.d.ts | 28 + dist/worker/declarations/room_delegate.d.ts | 16 + dist/worker/declarations/room_store.d.ts | 16 + .../declarations/room_subscription.d.ts | 15 + dist/worker/declarations/room_user_store.d.ts | 8 + dist/worker/declarations/token_provider.d.ts | 29 + dist/worker/declarations/user.d.ts | 23 + dist/worker/declarations/user_store_core.d.ts | 8 + .../declarations/user_subscription.d.ts | 38 + dist/worker/declarations/utils.d.ts | 5 + 93 files changed, 16365 insertions(+) create mode 100644 dist/react-native/chatkit.js create mode 100644 dist/react-native/declarations/attachment.d.ts create mode 100644 dist/react-native/declarations/basic_cursor.d.ts create mode 100644 dist/react-native/declarations/basic_message.d.ts create mode 100644 dist/react-native/declarations/basic_message_enricher.d.ts create mode 100644 dist/react-native/declarations/basic_user.d.ts create mode 100644 dist/react-native/declarations/chat_manager.d.ts create mode 100644 dist/react-native/declarations/chat_manager_delegate.d.ts create mode 100644 dist/react-native/declarations/constants.d.ts create mode 100644 dist/react-native/declarations/current_user.d.ts create mode 100644 dist/react-native/declarations/cursor.d.ts create mode 100644 dist/react-native/declarations/cursor_subscription.d.ts create mode 100644 dist/react-native/declarations/cursor_types.d.ts create mode 100644 dist/react-native/declarations/fetched_attachment.d.ts create mode 100644 dist/react-native/declarations/global_user_store.d.ts create mode 100644 dist/react-native/declarations/index.d.ts create mode 100644 dist/react-native/declarations/message.d.ts create mode 100644 dist/react-native/declarations/payload_deserializer.d.ts create mode 100644 dist/react-native/declarations/presence_payload.d.ts create mode 100644 dist/react-native/declarations/presence_state.d.ts create mode 100644 dist/react-native/declarations/presence_subscription.d.ts create mode 100644 dist/react-native/declarations/room.d.ts create mode 100644 dist/react-native/declarations/room_delegate.d.ts create mode 100644 dist/react-native/declarations/room_store.d.ts create mode 100644 dist/react-native/declarations/room_subscription.d.ts create mode 100644 dist/react-native/declarations/room_user_store.d.ts create mode 100644 dist/react-native/declarations/token_provider.d.ts create mode 100644 dist/react-native/declarations/user.d.ts create mode 100644 dist/react-native/declarations/user_store_core.d.ts create mode 100644 dist/react-native/declarations/user_subscription.d.ts create mode 100644 dist/react-native/declarations/utils.d.ts create mode 100644 dist/web/chatkit.js create mode 100644 dist/web/declarations/attachment.d.ts create mode 100644 dist/web/declarations/basic_cursor.d.ts create mode 100644 dist/web/declarations/basic_message.d.ts create mode 100644 dist/web/declarations/basic_message_enricher.d.ts create mode 100644 dist/web/declarations/basic_user.d.ts create mode 100644 dist/web/declarations/chat_manager.d.ts create mode 100644 dist/web/declarations/chat_manager_delegate.d.ts create mode 100644 dist/web/declarations/constants.d.ts create mode 100644 dist/web/declarations/current_user.d.ts create mode 100644 dist/web/declarations/cursor.d.ts create mode 100644 dist/web/declarations/cursor_subscription.d.ts create mode 100644 dist/web/declarations/cursor_types.d.ts create mode 100644 dist/web/declarations/fetched_attachment.d.ts create mode 100644 dist/web/declarations/global_user_store.d.ts create mode 100644 dist/web/declarations/index.d.ts create mode 100644 dist/web/declarations/message.d.ts create mode 100644 dist/web/declarations/payload_deserializer.d.ts create mode 100644 dist/web/declarations/presence_payload.d.ts create mode 100644 dist/web/declarations/presence_state.d.ts create mode 100644 dist/web/declarations/presence_subscription.d.ts create mode 100644 dist/web/declarations/room.d.ts create mode 100644 dist/web/declarations/room_delegate.d.ts create mode 100644 dist/web/declarations/room_store.d.ts create mode 100644 dist/web/declarations/room_subscription.d.ts create mode 100644 dist/web/declarations/room_user_store.d.ts create mode 100644 dist/web/declarations/token_provider.d.ts create mode 100644 dist/web/declarations/user.d.ts create mode 100644 dist/web/declarations/user_store_core.d.ts create mode 100644 dist/web/declarations/user_subscription.d.ts create mode 100644 dist/web/declarations/utils.d.ts create mode 100644 dist/worker/chatkit.worker.js create mode 100644 dist/worker/declarations/attachment.d.ts create mode 100644 dist/worker/declarations/basic_cursor.d.ts create mode 100644 dist/worker/declarations/basic_message.d.ts create mode 100644 dist/worker/declarations/basic_message_enricher.d.ts create mode 100644 dist/worker/declarations/basic_user.d.ts create mode 100644 dist/worker/declarations/chat_manager.d.ts create mode 100644 dist/worker/declarations/chat_manager_delegate.d.ts create mode 100644 dist/worker/declarations/constants.d.ts create mode 100644 dist/worker/declarations/current_user.d.ts create mode 100644 dist/worker/declarations/cursor.d.ts create mode 100644 dist/worker/declarations/cursor_subscription.d.ts create mode 100644 dist/worker/declarations/cursor_types.d.ts create mode 100644 dist/worker/declarations/fetched_attachment.d.ts create mode 100644 dist/worker/declarations/global_user_store.d.ts create mode 100644 dist/worker/declarations/index.d.ts create mode 100644 dist/worker/declarations/message.d.ts create mode 100644 dist/worker/declarations/payload_deserializer.d.ts create mode 100644 dist/worker/declarations/presence_payload.d.ts create mode 100644 dist/worker/declarations/presence_state.d.ts create mode 100644 dist/worker/declarations/presence_subscription.d.ts create mode 100644 dist/worker/declarations/room.d.ts create mode 100644 dist/worker/declarations/room_delegate.d.ts create mode 100644 dist/worker/declarations/room_store.d.ts create mode 100644 dist/worker/declarations/room_subscription.d.ts create mode 100644 dist/worker/declarations/room_user_store.d.ts create mode 100644 dist/worker/declarations/token_provider.d.ts create mode 100644 dist/worker/declarations/user.d.ts create mode 100644 dist/worker/declarations/user_store_core.d.ts create mode 100644 dist/worker/declarations/user_subscription.d.ts create mode 100644 dist/worker/declarations/utils.d.ts diff --git a/dist/react-native/chatkit.js b/dist/react-native/chatkit.js new file mode 100644 index 0000000..fa6a4dc --- /dev/null +++ b/dist/react-native/chatkit.js @@ -0,0 +1,4015 @@ +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 7); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var current_user_1 = __webpack_require__(11); +var presence_state_1 = __webpack_require__(4); +var room_1 = __webpack_require__(18); +var user_1 = __webpack_require__(20); +var utils_1 = __webpack_require__(1); +var checkPresenceAndTypeOfFieldsInPayload = function (requiredFieldsWithTypes, payload) { + Object.keys(requiredFieldsWithTypes).forEach(function (key) { + if (payload[key] === undefined) { + throw new Error("Payload missing key: " + key); + } + var receivedType = typeof payload[key]; + var expectedType = requiredFieldsWithTypes[key]; + if (receivedType !== expectedType) { + throw new Error("Value for key: " + key + " in payload was " + receivedType + ", expected " + expectedType); + } + }); +}; +var PayloadDeserializer = (function () { + function PayloadDeserializer() { + } + PayloadDeserializer.createUserFromPayload = function (userPayload) { + var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); + return new user_1.default({ + avatarURL: userPayload.avatar_url, + createdAt: basicUser.createdAt, + customData: userPayload.custom_data, + id: basicUser.id, + name: userPayload.name, + updatedAt: basicUser.updatedAt, + }); + }; + PayloadDeserializer.createCurrentUserFromPayload = function (userPayload, apiInstance, filesInstance, cursorsInstance, userStore) { + var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); + return new current_user_1.default({ + apiInstance: apiInstance, + avatarURL: userPayload.avatar_url, + createdAt: basicUser.createdAt, + cursorsInstance: cursorsInstance, + customData: userPayload.custom_data, + filesInstance: filesInstance, + id: basicUser.id, + name: userPayload.name, + updatedAt: basicUser.updatedAt, + userStore: userStore, + }); + }; + PayloadDeserializer.createRoomFromPayload = function (roomPayload) { + var requiredFieldsWithTypes = { + created_at: 'string', + created_by_id: 'string', + id: 'number', + name: 'string', + private: 'boolean', + updated_at: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, roomPayload); + var memberUserIds = []; + if (roomPayload.member_user_ids) { + memberUserIds = roomPayload.member_user_ids; + } + return new room_1.default({ + createdAt: roomPayload.created_at, + createdByUserId: roomPayload.created_by_id, + deletedAt: roomPayload.deleted_at, + id: roomPayload.id, + isPrivate: roomPayload.private, + name: roomPayload.name, + updatedAt: roomPayload.updated_at, + userIds: memberUserIds, + }); + }; + PayloadDeserializer.createBasicMessageFromPayload = function (messagePayload) { + var requiredFieldsWithTypes = { + created_at: 'string', + id: 'number', + room_id: 'number', + text: 'string', + updated_at: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, messagePayload); + var attachment = this.createAttachmentFromPayload(messagePayload.attachment); + return { + attachment: attachment, + createdAt: messagePayload.created_at, + id: messagePayload.id, + roomId: messagePayload.room_id, + senderId: messagePayload.user_id, + text: messagePayload.text, + updatedAt: messagePayload.updated_at, + }; + }; + PayloadDeserializer.createBasicCursorFromPayload = function (payload) { + var requiredFieldsWithTypes = { + cursor_type: 'number', + position: 'number', + room_id: 'number', + updated_at: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + return { + cursorType: payload.cursor_type, + position: payload.position, + roomId: payload.room_id, + updatedAt: payload.updated_at, + userId: payload.user_id, + }; + }; + PayloadDeserializer.createPresencePayloadFromPayload = function (payload) { + var requiredFieldsWithTypes = { + state: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var state = new presence_state_1.default(payload.state); + return { + lastSeenAt: payload.last_seen_at, + state: state, + userId: payload.user_id, + }; + }; + PayloadDeserializer.createBasicUserFromPayload = function (payload) { + var requiredFieldsWithTypes = { + created_at: 'string', + id: 'string', + updated_at: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + return { + createdAt: payload.created_at, + id: payload.id, + updatedAt: payload.updated_at, + }; + }; + PayloadDeserializer.createAttachmentFromPayload = function (payload) { + if (payload === undefined) { + return undefined; + } + var requiredFieldsWithTypes = { + resource_link: 'string', + type: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var linkQueryParams = utils_1.queryParamsFromFullUrl(payload.resource_link); + var fetchRequired = linkQueryParams.chatkit_link !== undefined && + linkQueryParams.chatkit_link === 'true'; + return { + fetchRequired: fetchRequired, + link: payload.resource_link, + type: payload.type, + }; + }; + PayloadDeserializer.createFetchedAttachmentFromPayload = function (payload) { + if (payload === undefined) { + return undefined; + } + var requiredFieldsWithTypes = { + file: 'object', + resource_link: 'string', + ttl: 'number', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var requiredFieldsWithTypesForFileField = { + bytes: 'number', + last_modified: 'number', + name: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypesForFileField, payload.file); + var file = payload.file; + var bytes = file.bytes, name = file.name; + return { + file: { + bytes: bytes, + lastModified: file.last_modified, + name: name, + }, + link: payload.resource_link, + ttl: payload.ttl, + }; + }; + return PayloadDeserializer; +}()); +exports.default = PayloadDeserializer; + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function urlEncode(data) { + return Object.keys(data) + .filter(function (key) { return data[key] !== undefined; }) + .map(function (key) { return key + "=" + encodeURIComponent(data[key]); }) + .join('&'); +} +exports.urlEncode = urlEncode; +function queryString(data) { + var encodedData = urlEncode(data); + return encodedData ? "?" + encodedData : ''; +} +exports.queryString = queryString; +function queryParamsFromFullUrl(url) { + if (url.indexOf('?') === -1) { + return {}; + } + var splitUrl = url.split('?'); + var queryStr = splitUrl.slice(1).join('&'); + return queryParamObject(queryStr); +} +exports.queryParamsFromFullUrl = queryParamsFromFullUrl; +function querylessUrlAndQueryObjectFromFullUrl(urlString) { + if (urlString.indexOf('?') === -1) { + return { + queryObject: {}, + querylessUrl: urlString, + }; + } + var splitUrl = urlString.split('?'); + var querylessUrl = splitUrl[0]; + var queryStr = splitUrl.slice(1).join('&'); + return { + queryObject: queryParamObject(queryStr), + querylessUrl: querylessUrl, + }; +} +function queryParamObject(queryParamString) { + return queryParamString + .split('&') + .map(function (str) { + var _a = str.split('='), key = _a[0], value = _a[1]; + return _b = {}, _b[key] = decodeURI(value), _b; + var _b; + }) + .reduce(function (prev, curr) { return Object.assign(prev, curr); }); +} +function mergeQueryParamsIntoUrl(urlString, queryParams) { + var _a = querylessUrlAndQueryObjectFromFullUrl(urlString), querylessUrl = _a.querylessUrl, queryObject = _a.queryObject; + var fullQueryString = queryString(Object.assign(queryObject, queryParams)); + return "" + querylessUrl + fullQueryString; +} +exports.mergeQueryParamsIntoUrl = mergeQueryParamsIntoUrl; +function allPromisesSettled(promises) { + return Promise.all(promises.map(function (p) { + return Promise.resolve(p).then(function (v) { return ({ + state: 'fulfilled', + value: v, + }); }, function (r) { return ({ + reason: r, + state: 'rejected', + }); }); + })); +} +exports.allPromisesSettled = allPromisesSettled; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(8); + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TYPING_REQ_TTL = 1500; +exports.TYPING_REQ_LEEWAY = 500; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var PresenceState = (function () { + function PresenceState(state) { + switch (state) { + case 'online': + this.stringValue = state; + break; + case 'offline': + this.stringValue = state; + break; + default: + this.stringValue = 'unknown'; + break; + } + } + return PresenceState; +}()); +exports.default = PresenceState; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var UserStoreCore = (function () { + function UserStoreCore(users) { + if (users === void 0) { users = new Array(); } + this.users = users; + } + UserStoreCore.prototype.addOrMerge = function (user) { + var existingUser = this.users.find(function (el) { return el.id === user.id; }); + if (existingUser) { + existingUser.updateWithPropertiesOfUser(user); + return existingUser; + } + else { + this.users.push(user); + return user; + } + }; + UserStoreCore.prototype.remove = function (id) { + var indexOfUser = this.users.findIndex(function (el) { return el.id === id; }); + if (indexOfUser === -1) { + return undefined; + } + var user = this.users[indexOfUser]; + this.users.splice(indexOfUser, 1); + return user; + }; + UserStoreCore.prototype.find = function (id) { + return this.users.find(function (el) { return el.id === id; }); + }; + return UserStoreCore; +}()); +exports.default = UserStoreCore; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var utils_1 = __webpack_require__(1); +var TokenProvider = (function () { + function TokenProvider(options) { + this.authContext = options.authContext || {}; + this.url = options.url; + } + Object.defineProperty(TokenProvider.prototype, "cacheIsStale", { + get: function () { + if (this.cachedAccessToken && this.cachedTokenExpiresAt) { + return this.unixTimeNow() > this.cachedTokenExpiresAt; + } + return true; + }, + enumerable: true, + configurable: true + }); + TokenProvider.prototype.fetchToken = function (tokenParams) { + var _this = this; + if (this.cacheIsStale) { + return this.makeAuthRequest().then(function (responseBody) { + var access_token = responseBody.access_token, expires_in = responseBody.expires_in; + _this.cache(access_token, expires_in); + return access_token; + }); + } + return new Promise(function (resolve, reject) { + resolve(_this.cachedAccessToken); + }); + }; + TokenProvider.prototype.clearToken = function (token) { + this.cachedAccessToken = undefined; + this.cachedTokenExpiresAt = undefined; + }; + TokenProvider.prototype.makeAuthRequest = function () { + var url; + var authRequestQueryParams = (this.authContext || {}).queryParams || {}; + if (this.userId === undefined) { + url = utils_1.mergeQueryParamsIntoUrl(this.url, authRequestQueryParams); + } + else { + var authContextWithUserId = __assign({ user_id: this.userId }, authRequestQueryParams); + url = utils_1.mergeQueryParamsIntoUrl(this.url, authContextWithUserId); + } + var authRequestHeaders = (this.authContext || {}).headers || {}; + var headers = __assign((_a = {}, _a['Content-Type'] = 'application/x-www-form-urlencoded', _a), authRequestHeaders); + var body = utils_1.urlEncode({ grant_type: 'client_credentials' }); + return pusher_platform_1.sendRawRequest({ + body: body, + headers: headers, + method: 'POST', + url: url, + }).then(function (res) { + return JSON.parse(res); + }); + var _a; + }; + TokenProvider.prototype.cache = function (accessToken, expiresIn) { + this.cachedAccessToken = accessToken; + this.cachedTokenExpiresAt = this.unixTimeNow() + expiresIn; + }; + TokenProvider.prototype.unixTimeNow = function () { + return Math.floor(Date.now() / 1000); + }; + return TokenProvider; +}()); +exports.default = TokenProvider; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +exports.BaseClient = pusher_platform_1.BaseClient; +var chat_manager_1 = __webpack_require__(9); +exports.ChatManager = chat_manager_1.default; +var token_provider_1 = __webpack_require__(6); +exports.TokenProvider = token_provider_1.default; +exports.default = { + BaseClient: pusher_platform_1.BaseClient, + ChatManager: chat_manager_1.default, + TokenProvider: token_provider_1.default, +}; + + +/***/ }), +/* 8 */ +/***/ (function(module, exports) { + +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 11); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function responseToHeadersObject(headerStr) { + var headers = {}; + if (!headerStr) { + return headers; + } + var headerPairs = headerStr.split('\u000d\u000a'); + for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { + var headerPair = headerPairs_1[_i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) { + var key = headerPair.substring(0, index); + var val = headerPair.substring(index + 2); + headers[key] = val; + } + } + return headers; +} +exports.responseToHeadersObject = responseToHeadersObject; +var ErrorResponse = (function () { + function ErrorResponse(statusCode, headers, info) { + this.statusCode = statusCode; + this.headers = headers; + this.info = info; + } + ErrorResponse.fromXHR = function (xhr) { + var errorInfo = xhr.responseText; + try { + errorInfo = JSON.parse(xhr.responseText); + } + catch (e) { + } + return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); + }; + return ErrorResponse; +}()); +exports.ErrorResponse = ErrorResponse; +var NetworkError = (function () { + function NetworkError(error) { + this.error = error; + } + return NetworkError; +}()); +exports.NetworkError = NetworkError; +var XhrReadyState; +(function (XhrReadyState) { + XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; + XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; + XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; + XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; + XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; +})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1,eval)("this"); +} catch(e) { + // This works if the window reference is available + if(typeof window === "object") + g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +Object.defineProperty(exports, "__esModule", { value: true }); +var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; + LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; + LogLevel[LogLevel["INFO"] = 3] = "INFO"; + LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; + LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; +})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); +var ConsoleLogger = (function () { + function ConsoleLogger(threshold) { + if (threshold === void 0) { threshold = 2; } + this.threshold = threshold; + var groups = Array(); + var hr = '--------------------------------------------------------------------------------'; + if (!global.console.group) { + global.console.group = function (label) { + groups.push(label); + global.console.log('%c \nBEGIN GROUP: %c', hr, label); + }; + } + if (!global.console.groupEnd) { + global.console.groupEnd = function () { + global.console.log('END GROUP: %c\n%c', groups.pop(), hr); + }; + } + } + ConsoleLogger.prototype.verbose = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(global.console.log, LogLevel.VERBOSE, items); + }; + ConsoleLogger.prototype.debug = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(global.console.log, LogLevel.DEBUG, items); + }; + ConsoleLogger.prototype.info = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(global.console.info, LogLevel.INFO, items); + }; + ConsoleLogger.prototype.warn = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(global.console.warn, LogLevel.WARNING, items); + }; + ConsoleLogger.prototype.error = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(global.console.error, LogLevel.ERROR, items); + }; + ConsoleLogger.prototype.log = function (logFunction, level, items) { + var _this = this; + if (level >= this.threshold) { + var loggerSignature_1 = "Logger." + LogLevel[level]; + if (items.length > 1) { + global.console.group(); + items.forEach(function (item) { + _this.errorAwareLog(logFunction, item, loggerSignature_1); + }); + global.console.groupEnd(); + } + else { + this.errorAwareLog(logFunction, items[0], loggerSignature_1); + } + } + }; + ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { + if (item.info && item.info.error_uri) { + var errorDesc = item.info.error_description; + var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; + logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); + } + else { + logFunction(loggerSignature + ": ", item); + } + }; + return ConsoleLogger; +}()); +exports.ConsoleLogger = ConsoleLogger; +var EmptyLogger = (function () { + function EmptyLogger() { + } + EmptyLogger.prototype.verbose = function (message, error) { }; + EmptyLogger.prototype.debug = function (message, error) { }; + EmptyLogger.prototype.info = function (message, error) { }; + EmptyLogger.prototype.warn = function (message, error) { }; + EmptyLogger.prototype.error = function (message, error) { }; + return EmptyLogger; +}()); +exports.EmptyLogger = EmptyLogger; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createRetryStrategyOptionsOrDefault = function (options) { + var initialTimeoutMillis = options.initialTimeoutMillis || 1000; + var maxTimeoutMillis = options.maxTimeoutMillis || 5000; + var limit = -1; + if (options.limit !== undefined && options.limit != null) { + limit = options.limit; + } + var increaseTimeout; + if (options.increaseTimeout !== undefined) { + increaseTimeout = options.increaseTimeout; + } + else { + increaseTimeout = function (currentTimeout) { + if (currentTimeout * 2 > maxTimeoutMillis) { + return maxTimeoutMillis; + } + else { + return currentTimeout * 2; + } + }; + } + return { + increaseTimeout: increaseTimeout, + initialTimeoutMillis: initialTimeoutMillis, + limit: limit, + maxTimeoutMillis: maxTimeoutMillis, + }; +}; +var Retry = (function () { + function Retry(waitTimeMillis) { + this.waitTimeMillis = waitTimeMillis; + } + return Retry; +}()); +exports.Retry = Retry; +var DoNotRetry = (function () { + function DoNotRetry(error) { + this.error = error; + } + return DoNotRetry; +}()); +exports.DoNotRetry = DoNotRetry; +var requestMethodIsSafe = function (method) { + method = method.toUpperCase(); + return (method === 'GET' || + method === 'HEAD' || + method === 'OPTIONS' || + method === 'SUBSCRIBE'); +}; +var RetryResolution = (function () { + function RetryResolution(options, logger, retryUnsafeRequests) { + this.options = options; + this.logger = logger; + this.retryUnsafeRequests = retryUnsafeRequests; + this.currentRetryCount = 0; + this.initialTimeoutMillis = options.initialTimeoutMillis; + this.maxTimeoutMillis = options.maxTimeoutMillis; + this.limit = options.limit; + this.increaseTimeoutFunction = options.increaseTimeout; + this.currentBackoffMillis = this.initialTimeoutMillis; + } + RetryResolution.prototype.attemptRetry = function (error) { + this.logger.verbose(this.constructor.name + ": Error received", error); + if (this.currentRetryCount >= this.limit && this.limit >= 0) { + this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); + return new DoNotRetry(error); + } + if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { + this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); + return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); + } + if (error instanceof network_1.NetworkError || + (error instanceof network_1.ErrorResponse && + requestMethodIsSafe(error.headers['Request-Method'])) || + this.retryUnsafeRequests) { + return this.shouldSafeRetry(error); + } + if (error instanceof network_1.NetworkError) { + return this.shouldSafeRetry(error); + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.shouldSafeRetry = function (error) { + if (error instanceof network_1.NetworkError) { + this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); + return new Retry(this.calulateMillisToRetry()); + } + else if (error instanceof network_1.ErrorResponse) { + if (error.statusCode >= 500 && error.statusCode < 600) { + this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); + return new Retry(this.calulateMillisToRetry()); + } + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.calulateMillisToRetry = function () { + this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); + this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); + return this.currentBackoffMillis; + }; + return RetryResolution; +}()); +exports.RetryResolution = RetryResolution; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var logger_1 = __webpack_require__(2); +var request_1 = __webpack_require__(5); +var resuming_subscription_1 = __webpack_require__(6); +var retrying_subscription_1 = __webpack_require__(7); +var subscribe_strategy_1 = __webpack_require__(12); +var subscription_1 = __webpack_require__(13); +var token_providing_subscription_1 = __webpack_require__(8); +var http_1 = __webpack_require__(14); +var websocket_1 = __webpack_require__(15); +var transports_1 = __webpack_require__(9); +var BaseClient = (function () { + function BaseClient(options) { + this.options = options; + this.host = options.host.replace(/(\/)+$/, ''); + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.websocketTransport = new websocket_1.default(this.host); + this.httpTransport = new http_1.default(this.host, options.encrypted); + } + BaseClient.prototype.request = function (options, tokenParams) { + var _this = this; + if (options.tokenProvider) { + return options.tokenProvider + .fetchToken(tokenParams) + .then(function (token) { + if (options.headers !== undefined) { + options.headers['Authorization'] = "Bearer " + token; + } + else { + options.headers = (_a = {}, + _a['Authorization'] = "Bearer " + token, + _a); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + var _a; + }) + .catch(function (error) { + _this.logger.error(error); + }); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + }; + BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + return BaseClient; +}()); +exports.BaseClient = BaseClient; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +function executeNetworkRequest(createXhr, options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); + sendBody(xhr, options); + }); +} +exports.executeNetworkRequest = executeNetworkRequest; +function sendBody(xhr, options) { + if (options.json) { + xhr.send(JSON.stringify(options.json)); + } + else { + xhr.send(options.body); + } +} +function sendRawRequest(options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(new global.XMLHttpRequest(), resolve, reject); + xhr.open(options.method.toUpperCase(), options.url, true); + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + xhr.send(options.body); + }); +} +exports.sendRawRequest = sendRawRequest; +function attachOnReadyStateChangeHandler(xhr, resolve, reject) { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.response); + } + else if (xhr.status !== 0) { + reject(network_1.ErrorResponse.fromXHR(xhr)); + } + else { + reject(new network_1.NetworkError('No Connection')); + } + } + }; + return xhr; +} + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(3); +exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { + var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); + var ResumingSubscription = (function () { + function ResumingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + this.onTransition = onTransition; + var lastEventId = initialEventId; + logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); + if (lastEventId) { + headers['Last-Event-Id'] = lastEventId; + logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); + } + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpeningSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpenSubscriptionState; + }()); + var ResumingSubscriptionState = (function () { + function ResumingSubscriptionState(error, onTransition, lastEventId) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); + var executeSubscriptionOnce = function (error, lastEventId) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = global.setTimeout(function () { + executeNextSubscribeStrategy(lastEventId); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function (lastEventId) { + logger.verbose("ResumingSubscription: trying to re-establish the subscription"); + if (lastEventId) { + logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); + headers['Last-Event-Id'] = lastEventId; + } + _this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + executeSubscriptionOnce(error, lastEventId); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error, lastEventId); + } + ResumingSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + global.clearTimeout(this.timeout); + this.underlyingSubscription.unsubscribe(); + }; + return ResumingSubscriptionState; + }()); + var EndingSubscriptionState = (function () { + function EndingSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); + } + EndingSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription is already ending'); + }; + return EndingSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return ResumingSubscription; + }()); + return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; +}; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(3); +exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { + var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); + var RetryingSubscription = (function () { + function RetryingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { + return onTransition(new RetryingSubscriptionState(error, onTransition)); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + throw new Error('Method not implemented.'); + }; + return OpeningSubscriptionState; + }()); + var RetryingSubscriptionState = (function () { + function RetryingSubscriptionState(error, onTransition) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); + var executeSubscriptionOnce = function (error) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = global.setTimeout(function () { + executeNextSubscribeStrategy(); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function () { + logger.verbose("RetryingSubscription: trying to re-establish the subscription"); + var underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { return executeSubscriptionOnce(error); }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error); + } + RetryingSubscriptionState.prototype.unsubscribe = function () { + global.clearTimeout(this.timeout); + this.onTransition(new EndedSubscriptionState()); + }; + return RetryingSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + this.onTransition(new EndedSubscriptionState()); + }; + return OpenSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return RetryingSubscription; + }()); + return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; +}; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { + if (tokenProvider) { + return function (listeners, headers) { + return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); + }; + } + return nextSubscribeStrategy; +}; +var TokenProvidingSubscription = (function () { + function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { + var _this = this; + this.logger = logger; + this.listeners = listeners; + this.headers = headers; + this.tokenProvider = tokenProvider; + this.nextSubscribeStrategy = nextSubscribeStrategy; + this.unsubscribe = function () { + _this.state.unsubscribe(); + _this.state = new InactiveState(_this.logger); + }; + this.state = new ActiveState(logger, headers, nextSubscribeStrategy); + this.subscribe(); + } + TokenProvidingSubscription.prototype.subscribe = function () { + var _this = this; + this.tokenProvider + .fetchToken() + .then(function (token) { + var existingListeners = Object.assign({}, _this.listeners); + _this.state.subscribe(token, { + onEnd: function (error) { + _this.state = new InactiveState(_this.logger); + existingListeners.onEnd(error); + }, + onError: function (error) { + if (_this.isTokenExpiredError(error)) { + _this.tokenProvider.clearToken(token); + _this.subscribe(); + } + else { + _this.state = new InactiveState(_this.logger); + existingListeners.onError(error); + } + }, + onEvent: _this.listeners.onEvent, + onOpen: _this.listeners.onOpen, + }); + }) + .catch(function (error) { + _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); + _this.state = new InactiveState(_this.logger); + _this.listeners.onError(error); + }); + }; + TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { + return (error instanceof network_1.ErrorResponse && + error.statusCode === 401 && + error.info === 'authentication/expired'); + }; + return TokenProvidingSubscription; +}()); +var ActiveState = (function () { + function ActiveState(logger, headers, nextSubscribeStrategy) { + this.logger = logger; + this.headers = headers; + this.nextSubscribeStrategy = nextSubscribeStrategy; + logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); + } + ActiveState.prototype.subscribe = function (token, listeners) { + var _this = this; + this.putTokenIntoHeader(token); + this.underlyingSubscription = this.nextSubscribeStrategy({ + onEnd: function (error) { + _this.logger.verbose("TokenProvidingSubscription: subscription ended"); + listeners.onEnd(error); + }, + onError: function (error) { + _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); + listeners.onError(error); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + _this.logger.verbose("TokenProvidingSubscription: subscription opened"); + listeners.onOpen(headers); + }, + onRetrying: listeners.onRetrying, + }, this.headers); + }; + ActiveState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + }; + ActiveState.prototype.putTokenIntoHeader = function (token) { + this.headers['Authorization'] = "Bearer " + token; + this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); + }; + return ActiveState; +}()); +var InactiveState = (function () { + function InactiveState(logger) { + this.logger = logger; + logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); + } + InactiveState.prototype.subscribe = function (token, listeners) { + this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); + }; + InactiveState.prototype.unsubscribe = function () { + this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); + }; + return InactiveState; +}()); + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createTransportStrategy = function (path, transport, logger) { + return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; +}; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HOST_BASE = 'pusherplatform.io'; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(4); +exports.BaseClient = base_client_1.BaseClient; +var host_base_1 = __webpack_require__(10); +exports.HOST_BASE = host_base_1.HOST_BASE; +var instance_1 = __webpack_require__(16); +exports.Instance = instance_1.default; +var logger_1 = __webpack_require__(2); +exports.ConsoleLogger = logger_1.ConsoleLogger; +exports.EmptyLogger = logger_1.EmptyLogger; +var network_1 = __webpack_require__(0); +exports.ErrorResponse = network_1.ErrorResponse; +exports.NetworkError = network_1.NetworkError; +exports.responseToHeadersObject = network_1.responseToHeadersObject; +exports.XhrReadyState = network_1.XhrReadyState; +var request_1 = __webpack_require__(5); +exports.executeNetworkRequest = request_1.executeNetworkRequest; +exports.sendRawRequest = request_1.sendRawRequest; +var resuming_subscription_1 = __webpack_require__(6); +exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; +var retry_strategy_1 = __webpack_require__(3); +exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; +exports.DoNotRetry = retry_strategy_1.DoNotRetry; +exports.Retry = retry_strategy_1.Retry; +exports.RetryResolution = retry_strategy_1.RetryResolution; +var retrying_subscription_1 = __webpack_require__(7); +exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; +var token_providing_subscription_1 = __webpack_require__(8); +exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; +var transports_1 = __webpack_require__(9); +exports.createTransportStrategy = transports_1.createTransportStrategy; +exports.default = { + BaseClient: base_client_1.BaseClient, + ConsoleLogger: logger_1.ConsoleLogger, + EmptyLogger: logger_1.EmptyLogger, + Instance: instance_1.default, +}; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { + return { + onEnd: subListeners.onEnd, + onError: subListeners.onError, + onEvent: subListeners.onEvent, + onOpen: subListeners.onOpen, + onRetrying: subListeners.onRetrying, + }; +}; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.replaceMissingListenersWithNoOps = function (listeners) { + var onEndNoOp = function (error) { }; + var onEnd = listeners.onEnd || onEndNoOp; + var onErrorNoOp = function (error) { }; + var onError = listeners.onError || onErrorNoOp; + var onEventNoOp = function (event) { }; + var onEvent = listeners.onEvent || onEventNoOp; + var onOpenNoOp = function (headers) { }; + var onOpen = listeners.onOpen || onOpenNoOp; + var onRetryingNoOp = function () { }; + var onRetrying = listeners.onRetrying || onRetryingNoOp; + var onSubscribeNoOp = function () { }; + var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; + return { + onEnd: onEnd, + onError: onError, + onEvent: onEvent, + onOpen: onOpen, + onRetrying: onRetrying, + onSubscribe: onSubscribe, + }; +}; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var HttpTransportState; +(function (HttpTransportState) { + HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; + HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; + HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; + HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; + HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; +})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); +var HttpSubscription = (function () { + function HttpSubscription(xhr, listeners) { + var _this = this; + this.gotEOS = false; + this.lastNewlineIndex = 0; + this.state = HttpTransportState.UNOPENED; + this.xhr = xhr; + this.listeners = listeners; + this.xhr.onreadystatechange = function () { + switch (_this.xhr.readyState) { + case network_1.XhrReadyState.UNSENT: + case network_1.XhrReadyState.OPENED: + case network_1.XhrReadyState.HEADERS_RECEIVED: + _this.assertStateIsIn(HttpTransportState.OPENING); + break; + case network_1.XhrReadyState.LOADING: + _this.onLoading(); + break; + case network_1.XhrReadyState.DONE: + _this.onDone(); + break; + } + }; + this.state = HttpTransportState.OPENING; + this.xhr.send(); + return this; + } + HttpSubscription.prototype.unsubscribe = function () { + this.state = HttpTransportState.ENDED; + this.xhr.abort(); + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + }; + HttpSubscription.prototype.onLoading = function () { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + global.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN); + var err = this.onChunk(); + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + if (err) { + this.state = HttpTransportState.ENDED; + if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else { + } + } + }; + HttpSubscription.prototype.onDone = function () { + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + var err = this.onChunk(); + if (err) { + this.state = HttpTransportState.ENDED; + if (err.statusCode === 204) { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else if (this.state <= HttpTransportState.ENDING) { + if (this.listeners.onError) { + this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); + } + } + else { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + } + else { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); + if (this.state === HttpTransportState.ENDED) { + return; + } + else if (this.xhr.status === 0) { + if (this.listeners.onError) { + this.listeners.onError(new network_1.NetworkError('Connection lost.')); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); + } + } + } + }; + HttpSubscription.prototype.onChunk = function () { + this.assertStateIsIn(HttpTransportState.OPEN); + var response = this.xhr.responseText; + var newlineIndex = response.lastIndexOf('\n'); + if (newlineIndex > this.lastNewlineIndex) { + var rawEvents = response + .slice(this.lastNewlineIndex, newlineIndex) + .split('\n'); + this.lastNewlineIndex = newlineIndex; + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + if (rawEvent.length === 0) { + continue; + } + var data = JSON.parse(rawEvent); + var err = this.onMessage(data); + if (err != null) { + return err; + } + } + } + }; + HttpSubscription.prototype.assertStateIsIn = function () { + var _this = this; + var validStates = []; + for (var _i = 0; _i < arguments.length; _i++) { + validStates[_i] = arguments[_i]; + } + var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); + if (!stateIsValid) { + var expectedStates = validStates + .map(function (state) { return HttpTransportState[state]; }) + .join(', '); + var actualState = HttpTransportState[this.state]; + global.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); + } + }; + HttpSubscription.prototype.onMessage = function (message) { + this.assertStateIsIn(HttpTransportState.OPEN); + this.verifyMessage(message); + switch (message[0]) { + case 0: + return null; + case 1: + return this.onEventMessage(message); + case 255: + return this.onEOSMessage(message); + default: + return new Error('Unknown Message: ' + JSON.stringify(message)); + } + }; + HttpSubscription.prototype.onEventMessage = function (eventMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eventMessage.length !== 4) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; + if (typeof id !== 'string') { + return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); + } + if (this.listeners.onEvent) { + this.listeners.onEvent({ body: body, headers: headers, eventId: id }); + } + return null; + }; + HttpSubscription.prototype.onEOSMessage = function (eosMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eosMessage.length !== 4) { + return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); + } + var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; + if (typeof statusCode !== 'number') { + return new Error('Invalid EOS Status Code'); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid EOS ElementsHeaders'); + } + this.state = HttpTransportState.ENDING; + return new network_1.ErrorResponse(statusCode, headers, info); + }; + HttpSubscription.prototype.verifyMessage = function (message) { + if (this.gotEOS) { + return new Error('Got another message after EOS message'); + } + if (!Array.isArray(message)) { + return new Error('Message is not an array'); + } + if (message.length < 1) { + return new Error('Message is empty array'); + } + }; + return HttpSubscription; +}()); +var HttpTransport = (function () { + function HttpTransport(host, encrypted) { + if (encrypted === void 0) { encrypted = true; } + this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; + } + HttpTransport.prototype.request = function (requestOptions) { + return this.createXHR(this.baseURL, requestOptions); + }; + HttpTransport.prototype.subscribe = function (path, listeners, headers) { + var requestOptions = { + headers: headers, + method: 'SUBSCRIBE', + path: path, + }; + return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); + }; + HttpTransport.prototype.createXHR = function (baseURL, options) { + var xhr = new global.XMLHttpRequest(); + var path = options.path.replace(/^\/+/, ''); + var endpoint = baseURL + "/" + path; + xhr.open(options.method.toUpperCase(), endpoint, true); + xhr = this.setJSONHeaderIfAppropriate(xhr, options); + if (options.jwt) { + xhr.setRequestHeader('authorization', "Bearer " + options.jwt); + } + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + return xhr; + }; + HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { + if (options.json) { + xhr.setRequestHeader('content-type', 'application/json'); + } + return xhr; + }; + return HttpTransport; +}()); +exports.default = HttpTransport; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var SubscribeMessageType = 100; +var OpenMessageType = 101; +var EventMessageType = 102; +var UnsubscribeMessageType = 198; +var EosMessageType = 199; +var PingMessageType = 16; +var PongMessageType = 17; +var CloseMessageType = 99; +var WSReadyState; +(function (WSReadyState) { + WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; + WSReadyState[WSReadyState["Open"] = 1] = "Open"; + WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; + WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; +})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); +var WsSubscriptions = (function () { + function WsSubscriptions() { + this.subscriptions = {}; + } + WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { + this.subscriptions[subID] = { + headers: headers, + listeners: listeners, + path: path, + }; + return subID; + }; + WsSubscriptions.prototype.has = function (subID) { + return this.subscriptions[subID] !== undefined; + }; + WsSubscriptions.prototype.isEmpty = function () { + return Object.keys(this.subscriptions).length === 0; + }; + WsSubscriptions.prototype.remove = function (subID) { + return delete this.subscriptions[subID]; + }; + WsSubscriptions.prototype.get = function (subID) { + return this.subscriptions[subID]; + }; + WsSubscriptions.prototype.getAll = function () { + return this.subscriptions; + }; + WsSubscriptions.prototype.getAllAsArray = function () { + var _this = this; + return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); + }; + WsSubscriptions.prototype.removeAll = function () { + this.subscriptions = {}; + }; + return WsSubscriptions; +}()); +var WsSubscription = (function () { + function WsSubscription(wsTransport, subID) { + this.wsTransport = wsTransport; + this.subID = subID; + } + WsSubscription.prototype.unsubscribe = function () { + this.wsTransport.unsubscribe(this.subID); + }; + return WsSubscription; +}()); +var pingIntervalMs = 30000; +var pingTimeoutMs = 10000; +var WebSocketTransport = (function () { + function WebSocketTransport(host) { + this.webSocketPath = '/ws'; + this.forcedClose = false; + this.closedError = null; + this.baseURL = "wss://" + host + this.webSocketPath; + this.lastSubscriptionID = 0; + this.subscriptions = new WsSubscriptions(); + this.pendingSubscriptions = new WsSubscriptions(); + this.connect(); + } + WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { + this.tryReconnectIfNeeded(); + var subID = this.lastSubscriptionID++; + if (this.socket.readyState !== WSReadyState.Open) { + this.pendingSubscriptions.add(subID, path, listeners, headers); + return new WsSubscription(this, subID); + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + return new WsSubscription(this, subID); + }; + WebSocketTransport.prototype.unsubscribe = function (subID) { + this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); + var subscription = this.subscriptions.get(subID); + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + this.subscriptions.remove(subID); + }; + WebSocketTransport.prototype.connect = function () { + var _this = this; + this.close(); + this.forcedClose = false; + this.closedError = null; + this.socket = new global.WebSocket(this.baseURL); + this.socket.onopen = function (event) { + var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); + allPendingSubscriptions.forEach(function (subscription) { + var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; + _this.subscribePending(path, listeners, headers, subID); + }); + _this.pendingSubscriptions.removeAll(); + _this.pingInterval = global.setInterval(function () { + if (_this.pongTimeout) { + return; + } + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + return; + } + _this.sendMessage(_this.getMessage(PingMessageType, now)); + _this.lastSentPingID = now; + _this.pongTimeout = global.setTimeout(function () { + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + _this.pongTimeout = null; + return; + } + _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); + }, pingTimeoutMs); + }, pingIntervalMs); + }; + this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; + this.socket.onerror = function (event) { + _this.close(new network_1.NetworkError('Connection was lost.')); + }; + this.socket.onclose = function (event) { + if (!_this.forcedClose) { + _this.tryReconnectIfNeeded(); + return; + } + var callback = _this.closedError + ? function (subscription) { + if (subscription.listeners.onError) { + subscription.listeners.onError(_this.closedError); + } + } + : function (subscription) { + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + }; + var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false + ? _this.pendingSubscriptions + : _this.subscriptions; + allSubscriptions.getAllAsArray().forEach(callback); + allSubscriptions.removeAll(); + if (_this.closedError) { + _this.tryReconnectIfNeeded(); + } + }; + }; + WebSocketTransport.prototype.close = function (error) { + if (!(this.socket instanceof global.WebSocket)) { + return; + } + this.forcedClose = true; + this.closedError = error; + this.socket.close(); + global.clearTimeout(this.pingInterval); + global.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.tryReconnectIfNeeded = function () { + if (this.socket.readyState !== WSReadyState.Closed) { + return; + } + this.connect(); + }; + WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { + if (subID === undefined) { + global.console.logger.debug("Subscription to path " + path + " has an undefined ID"); + return; + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + }; + WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { + return [messageType, id, path, headers]; + }; + WebSocketTransport.prototype.sendMessage = function (message) { + if (this.socket.readyState !== WSReadyState.Open) { + return global.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); + } + this.socket.send(JSON.stringify(message)); + }; + WebSocketTransport.prototype.subscription = function (subID) { + return this.subscriptions.get(subID); + }; + WebSocketTransport.prototype.receiveMessage = function (event) { + this.lastMessageReceivedTimestamp = new Date().getTime(); + var message; + try { + message = JSON.parse(event.data); + } + catch (err) { + this.close(new Error("Message is not valid JSON format. Getting " + event.data)); + return; + } + var nonValidMessageError = this.validateMessage(message); + if (nonValidMessageError) { + this.close(new Error(nonValidMessageError.message)); + return; + } + var messageType = message.shift(); + switch (messageType) { + case PongMessageType: + this.onPongMessage(message); + return; + case PingMessageType: + this.onPingMessage(message); + return; + case CloseMessageType: + this.onCloseMessage(message); + return; + } + var subID = message.shift(); + var subscription = this.subscription(subID); + if (!subscription) { + this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); + return; + } + var listeners = subscription.listeners; + switch (messageType) { + case OpenMessageType: + this.onOpenMessage(message, subID, listeners); + break; + case EventMessageType: + this.onEventMessage(message, listeners); + break; + case EosMessageType: + this.onEOSMessage(message, subID, listeners); + break; + default: + this.close(new Error('Received non existing type of message.')); + } + }; + WebSocketTransport.prototype.validateMessage = function (message) { + if (!Array.isArray(message)) { + return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); + } + if (message.length < 1) { + return new Error("Message is empty array: " + JSON.stringify(message)); + } + return null; + }; + WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { + if (subscriptionListeners.onOpen) { + subscriptionListeners.onOpen(message[1]); + } + }; + WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { + if (eventMessage.length !== 3) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; + if (typeof eventId !== 'string') { + return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); + } + if (subscriptionListeners.onEvent) { + subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); + } + }; + WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { + this.subscriptions.remove(subID); + if (eosMessage.length !== 3) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); + } + return; + } + var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; + if (typeof statusCode !== 'number') { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS Status Code')); + } + return; + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); + } + return; + } + if (statusCode === 204) { + if (subscriptionListeners.onEnd) { + subscriptionListeners.onEnd(null); + } + return; + } + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); + } + return; + }; + WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { + var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; + if (typeof statusCode !== 'number') { + return this.close(new Error('Close message: Invalid EOS Status Code')); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); + } + this.close(); + }; + WebSocketTransport.prototype.onPongMessage = function (message) { + var receviedPongID = message[0]; + if (this.lastSentPingID !== receviedPongID) { + this.close(new network_1.NetworkError("Didn't received pong with proper ID")); + } + global.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.onPingMessage = function (message) { + var receviedPingID = message[0]; + this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); + }; + return WebSocketTransport; +}()); +exports.default = WebSocketTransport; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(4); +var host_base_1 = __webpack_require__(10); +var logger_1 = __webpack_require__(2); +var Instance = (function () { + function Instance(options) { + if (!options.locator) { + throw new Error('Expected `locator` property in Instance options!'); + } + var splitInstanceLocator = options.locator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instance locator property is in the wrong format!'); + } + if (!options.serviceName) { + throw new Error('Expected `serviceName` property in Instance options!'); + } + if (!options.serviceVersion) { + throw new Error('Expected `serviceVersion` property in Instance otpions!'); + } + this.platformVersion = splitInstanceLocator[0]; + this.cluster = splitInstanceLocator[1]; + this.id = splitInstanceLocator[2]; + this.serviceName = options.serviceName; + this.serviceVersion = options.serviceVersion; + this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.client = + options.client || + new base_client_1.BaseClient({ + encrypted: options.encrypted, + host: this.host, + logger: this.logger, + }); + this.tokenProvider = options.tokenProvider; + } + Instance.prototype.request = function (options, tokenParams) { + options.path = this.absPath(options.path); + if (options.headers == null || options.headers === undefined) { + options.headers = {}; + } + options.tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.request(options, tokenParams); + }; + Instance.prototype.subscribeNonResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); + }; + Instance.prototype.subscribeResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); + }; + Instance.prototype.absPath = function (relativePath) { + return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) + .replace(/\/+/g, '/') + .replace(/\/+$/, ''); + }; + return Instance; +}()); +exports.default = Instance; + + +/***/ }) +/******/ ]); + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var global_user_store_1 = __webpack_require__(10); +var payload_deserializer_1 = __webpack_require__(0); +var token_provider_1 = __webpack_require__(6); +var user_subscription_1 = __webpack_require__(21); +var ChatManager = (function () { + function ChatManager(options) { + if (typeof options.userId !== 'string') { + throw new Error('Please provide a userId to the ChatManger constructor!'); + } + this.userId = options.userId; + var splitInstanceLocator = options.instanceLocator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instanceLocator property is in the wrong format!'); + } + var cluster = splitInstanceLocator[1]; + var baseClient = options.baseClient || + new pusher_platform_1.BaseClient({ + host: cluster + "." + pusher_platform_1.HOST_BASE, + logger: options.logger, + }); + if (options.tokenProvider instanceof token_provider_1.default) { + options.tokenProvider.userId = this.userId; + } + var sharedInstanceOptions = { + client: baseClient, + locator: options.instanceLocator, + logger: options.logger, + tokenProvider: options.tokenProvider, + }; + this.apiInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.filesInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_files', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.cursorsInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_cursors', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.userStore = new global_user_store_1.default({ apiInstance: this.apiInstance }); + } + ChatManager.prototype.connect = function (options) { + var _this = this; + var cursorsReq = this.cursorsInstance + .request({ + method: 'GET', + path: "/cursors/0/users/" + this.userId, + }) + .then(function (res) { + var cursors = JSON.parse(res); + var cursorsByRoom = {}; + cursors.forEach(function (c) { + cursorsByRoom[c.room_id] = payload_deserializer_1.default.createBasicCursorFromPayload(c); + }); + return cursorsByRoom; + }) + .catch(function (err) { + _this.cursorsInstance.logger.verbose('Error getting cursors:', err); + return {}; + }); + this.userSubscription = new user_subscription_1.default({ + apiInstance: this.apiInstance, + connectCompletionHandler: function (currentUser, error) { + if (currentUser) { + currentUser.cursorsReq = cursorsReq + .then(function (cursors) { + currentUser.cursors = cursors; + }); + options.onSuccess(currentUser); + } + else { + options.onError(error); + } + }, + cursorsInstance: this.cursorsInstance, + delegate: options.delegate, + filesInstance: this.filesInstance, + userStore: this.userStore, + }); + this.apiInstance.subscribeNonResuming({ + listeners: { + onError: options.onError, + onEvent: this.userSubscription.handleEvent.bind(this.userSubscription), + }, + path: '/users', + }); + }; + return ChatManager; +}()); +exports.default = ChatManager; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var user_store_core_1 = __webpack_require__(5); +var utils_1 = __webpack_require__(1); +var GlobalUserStore = (function () { + function GlobalUserStore(options) { + this.apiInstance = options.apiInstance; + this.userStoreCore = options.userStoreCore || new user_store_core_1.default(); + } + GlobalUserStore.prototype.addOrMerge = function (user) { + return this.userStoreCore.addOrMerge(user); + }; + GlobalUserStore.prototype.remove = function (id) { + return this.userStoreCore.remove(id); + }; + GlobalUserStore.prototype.user = function (id, onSuccess, onError) { + this.findOrGetUser(id, onSuccess, onError); + }; + GlobalUserStore.prototype.findOrGetUser = function (id, onSuccess, onError) { + var user = this.userStoreCore.find(id); + if (user) { + onSuccess(user); + return; + } + this.getUser(id, onSuccess, onError); + }; + GlobalUserStore.prototype.getUser = function (id, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: "/users/" + id, + }) + .then(function (res) { + var userPayload = JSON.parse(res); + var user = payload_deserializer_1.default.createUserFromPayload(userPayload); + var userToReturn = _this.addOrMerge(user); + onSuccess(userToReturn); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + onError(error); + }); + }; + GlobalUserStore.prototype.handleInitialPresencePayloadsAfterRoomJoin = function (payloads, onComplete) { + this.handleInitialPresencePayloads(payloads, onComplete); + }; + GlobalUserStore.prototype.handleInitialPresencePayloads = function (payloads, onComplete) { + var _this = this; + var presencePayloadPromises = new Array(); + payloads.forEach(function (payload) { + var presencePromise = new Promise(function (resolve, reject) { + _this.user(payload.userId, function (user) { + user.updatePresenceInfoIfAppropriate(payload); + resolve(); + }, function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + reject(); + }); + }); + presencePayloadPromises.push(presencePromise); + }); + utils_1.allPromisesSettled(presencePayloadPromises).then(function () { + onComplete(); + }); + }; + GlobalUserStore.prototype.fetchUsersWithIds = function (userIds, onSuccess, onError) { + var _this = this; + if (userIds.length === 0) { + this.apiInstance.logger.verbose('Requested to fetch users for a list of user ids which was empty'); + onSuccess([]); + return; + } + var userIdsString = userIds.join(','); + var qs = utils_1.queryString({ user_ids: userIdsString }); + this.apiInstance + .request({ + method: 'GET', + path: "/users_by_ids" + qs, + }) + .then(function (res) { + var usersPayload = JSON.parse(res); + var users = usersPayload.map(function (userPayload) { + var user = payload_deserializer_1.default.createUserFromPayload(userPayload); + var addedOrUpdatedUser = _this.userStoreCore.addOrMerge(user); + return addedOrUpdatedUser; + }); + onSuccess(users); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + onError(error); + }); + }; + GlobalUserStore.prototype.initialFetchOfUsersWithIds = function (userIds, onSuccess, onError) { + this.fetchUsersWithIds(userIds, onSuccess, onError); + }; + return GlobalUserStore; +}()); +exports.default = GlobalUserStore; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var basic_message_enricher_1 = __webpack_require__(12); +var cursor_subscription_1 = __webpack_require__(13); +var cursor_types_1 = __webpack_require__(14); +var payload_deserializer_1 = __webpack_require__(0); +var presence_subscription_1 = __webpack_require__(15); +var room_store_1 = __webpack_require__(16); +var room_subscription_1 = __webpack_require__(17); +var constants_1 = __webpack_require__(3); +var utils_1 = __webpack_require__(1); +var CurrentUser = (function () { + function CurrentUser(options) { + var rooms = options.rooms, id = options.id, apiInstance = options.apiInstance, filesInstance = options.filesInstance, cursorsInstance = options.cursorsInstance; + var validRooms = rooms || []; + this.id = id; + this.createdAt = options.createdAt; + this.cursors = {}; + this.updatedAt = options.updatedAt; + this.name = options.name; + this.avatarURL = options.avatarURL; + this.customData = options.customData; + this.roomStore = new room_store_1.default({ apiInstance: apiInstance, rooms: validRooms }); + this.apiInstance = apiInstance; + this.filesInstance = filesInstance; + this.cursorsInstance = cursorsInstance; + this.userStore = options.userStore; + this.pathFriendlyId = encodeURIComponent(id); + this.typingRequestSent = {}; + } + Object.defineProperty(CurrentUser.prototype, "rooms", { + get: function () { + return this.roomStore.rooms; + }, + enumerable: true, + configurable: true + }); + CurrentUser.prototype.updateWithPropertiesOf = function (currentUser) { + this.updatedAt = currentUser.updatedAt; + this.name = currentUser.name; + this.customData = currentUser.customData; + }; + CurrentUser.prototype.setupPresenceSubscription = function (delegate) { + this.presenceSubscription = new presence_subscription_1.default({ + apiInstance: this.apiInstance, + delegate: delegate, + roomStore: this.roomStore, + userStore: this.userStore, + }); + this.apiInstance.subscribeNonResuming({ + listeners: { + onError: delegate && delegate.error, + onEvent: this.presenceSubscription.handleEvent.bind(this.presenceSubscription), + }, + path: "/users/" + this.id + "/presence", + }); + }; + CurrentUser.prototype.createRoom = function (options, onSuccess, onError) { + var _this = this; + var roomData = { + created_by_id: this.id, + name: options.name, + private: options.private || false, + }; + if (options.addUserIds && options.addUserIds.length > 0) { + roomData['user_ids'] = options.addUserIds; + } + this.apiInstance + .request({ + json: roomData, + method: 'POST', + path: '/rooms', + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var addedOrMergedRoom = _this.roomStore.addOrMerge(room); + _this.populateRoomUserStore(addedOrMergedRoom); + onSuccess(addedOrMergedRoom); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error creating room:', error); + onError(error); + }); + }; + CurrentUser.prototype.populateRoomUserStore = function (room) { + var _this = this; + var userPromises = new Array(); + room.userIds.forEach(function (userId) { + var userPromise = new Promise(function (resolve, reject) { + _this.userStore.user(userId, function (user) { + room.userStore.addOrMerge(user); + resolve(); + }, function (error) { + _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room (room.name): " + error); + reject(); + }); + }); + userPromises.push(userPromise); + }); + utils_1.allPromisesSettled(userPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }; + CurrentUser.prototype.addUser = function (id, roomId, onSuccess, onError) { + this.addOrRemoveUsers(roomId, [id], 'add', onSuccess, onError); + }; + CurrentUser.prototype.removeUser = function (id, roomId, onSuccess, onError) { + this.addOrRemoveUsers(roomId, [id], 'remove', onSuccess, onError); + }; + CurrentUser.prototype.updateRoom = function (roomId, options, onSuccess, onError) { + var _this = this; + if (options.name === undefined && options.isPrivate === undefined) { + onSuccess(); + return; + } + var roomPayload = {}; + if (options.name) { + roomPayload['name'] = options.name; + } + if (options.isPrivate) { + roomPayload['private'] = options.isPrivate; + } + this.apiInstance + .request({ + json: roomPayload, + method: 'PUT', + path: "/rooms/" + roomId, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error updating room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.deleteRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'DELETE', + path: "/rooms/" + roomId, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error deleting room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.addOrRemoveUsers = function (roomId, userIds, membershipChange, onSuccess, onError) { + var _this = this; + var usersPayload = { + user_ids: userIds, + }; + this.apiInstance + .request({ + json: usersPayload, + method: 'PUT', + path: "/rooms/" + roomId + "/users/" + membershipChange, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error when attempting to " + membershipChange + " users from room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.joinRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'POST', + path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/join", + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var addedOrMergedRoom = _this.roomStore.addOrMerge(room); + _this.populateRoomUserStore(addedOrMergedRoom); + onSuccess(addedOrMergedRoom); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error joining room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.leaveRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'POST', + path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/leave", + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error leaving room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.getJoinedRooms = function (onSuccess, onError) { + this.getUserRooms(false, onSuccess, onError); + }; + CurrentUser.prototype.getJoinableRooms = function (onSuccess, onError) { + this.getUserRooms(true, onSuccess, onError); + }; + CurrentUser.prototype.getUserRooms = function (onlyJoinable, onSuccess, onError) { + var joinableQueryItemValue = onlyJoinable ? 'true' : 'false'; + this.getRooms("/users/" + this.pathFriendlyId + "/rooms?joinable=" + joinableQueryItemValue, onSuccess, onError); + }; + CurrentUser.prototype.getAllRooms = function (onSuccess, onError) { + this.getRooms('/rooms', onSuccess, onError); + }; + CurrentUser.prototype.isTypingIn = function (roomId, onSuccess, onError) { + var _this = this; + var now = Date.now(); + var sent = this.typingRequestSent[roomId]; + var eventName = 'typing_start'; + var eventPayload = { + name: 'typing_start', + user_id: this.id, + }; + if (!sent || now - sent > constants_1.TYPING_REQ_TTL - constants_1.TYPING_REQ_LEEWAY) { + this.typingRequestSent[roomId] = now; + this.apiInstance + .request({ + json: eventPayload, + method: 'POST', + path: "/rooms/" + roomId + "/events", + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + delete _this.typingRequestSent[roomId]; + _this.apiInstance.logger.verbose("Error sending " + eventName + " event in room " + roomId + ":", error); + onError(error); + }); + } + else { + onSuccess(); + } + }; + CurrentUser.prototype.setCursor = function (position, room, onSuccess, onError) { + var _this = this; + if (typeof position !== 'number') { + throw new Error('Cursor position should be a valid number'); + } + this.cursorsInstance + .request({ + json: { position: position }, + method: 'PUT', + path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id + "/users/" + this.id, + }) + .then(onSuccess) + .catch(function (err) { + _this.cursorsInstance.logger.verbose("Error setting cursor in room " + room.name + ":", err); + onError(err); + }); + }; + CurrentUser.prototype.sendMessage = function (options, onSuccess, onError) { + var _this = this; + var attachment = options.attachment, rest = __rest(options, ["attachment"]); + var completeOptions = __assign({ user_id: this.id }, rest); + if (attachment !== undefined) { + if (this.isDataAttachment(attachment)) { + var file = attachment.file, name = attachment.name; + this.uploadFile(file, name, options.roomId) + .then(function (fileRes) { + _this.sendMessageWithCompleteOptions(__assign({ attachment: fileRes, user_id: _this.id }, rest), onSuccess, onError); + }) + .catch(function (error) { + onError(error); + return; + }); + } + else if (this.isLinkAttachment(attachment)) { + var link = attachment.link, type = attachment.type; + completeOptions.attachment = { + resource_link: link, + type: type, + }; + this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); + } + else { + this.apiInstance.logger.debug('Message not sent: invalid attachment property provided: ', attachment); + } + } + else { + this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); + } + }; + CurrentUser.prototype.subscribeToRoom = function (room, roomDelegate, messageLimit) { + var _this = this; + var path = "/rooms/" + room.id; + if (messageLimit !== undefined) { + if (typeof messageLimit !== 'number') { + throw new Error('Message limit should be a valid number'); + } + path = path + "?message_limit=" + messageLimit; + } + this.cursorsReq.then(function () { + room.subscription = new room_subscription_1.default({ + basicMessageEnricher: new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger), + delegate: roomDelegate, + logger: _this.apiInstance.logger, + }); + _this.apiInstance.subscribeNonResuming({ + listeners: { + onError: roomDelegate.error, + onEvent: room.subscription.handleEvent.bind(room.subscription), + }, + path: path, + }); + _this.subscribeToCursors(room, roomDelegate); + }); + }; + CurrentUser.prototype.fetchMessagesFromRoom = function (room, fetchOptions, onSuccess, onError) { + var _this = this; + var initialIdQueryParam = fetchOptions.initialId + ? "initial_id=" + fetchOptions.initialId + : ''; + var limitQueryParam = fetchOptions.limit + ? "limit=" + fetchOptions.limit + : ''; + var directionQueryParam = fetchOptions.direction + ? "direction=" + fetchOptions.direction + : 'direction=older'; + var combinedQueryParams = [ + initialIdQueryParam, + limitQueryParam, + directionQueryParam, + ].join('&'); + this.apiInstance + .request({ + method: 'GET', + path: "/rooms/" + room.id + "/messages?" + combinedQueryParams, + }) + .then(function (res) { + var messagesPayload = JSON.parse(res); + var messages = new Array(); + var basicMessages = new Array(); + var messageUserIds = messagesPayload.map(function (messagePayload) { + var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(messagePayload); + basicMessages.push(basicMessage); + return basicMessage.id; + }); + var messageUserIdsSet = new Set(messageUserIds); + var userIdsToFetch = Array.from(messageUserIdsSet.values()); + _this.userStore.fetchUsersWithIds(userIdsToFetch, function (users) { + var messageEnricher = new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger); + var enrichmentPromises = new Array(); + basicMessages.forEach(function (basicMessage) { + var enrichmentPromise = new Promise(function (resolve, reject) { + messageEnricher.enrich(basicMessage, function (message) { + messages.push(message); + resolve(); + }, function (error) { + _this.apiInstance.logger.verbose("Unable to enrich basic mesage " + basicMessage.id + ": " + error); + reject(); + }); + }); + enrichmentPromises.push(enrichmentPromise); + }); + utils_1.allPromisesSettled(enrichmentPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + onSuccess(messages.sort(function (msgOne, msgTwo) { return msgOne.id - msgTwo.id; })); + }); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching users with ids " + userIdsToFetch + ":", error); + }); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error fetching messages froom room " + room.name + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.fetchAttachment = function (attachmentURL) { + if (!this.apiInstance.tokenProvider) { + return new Promise(function (resolve, reject) { + reject(new Error('Token provider not set on apiInstance')); + }); + } + return this.apiInstance.tokenProvider.fetchToken().then(function (token) { + return pusher_platform_1.sendRawRequest({ + headers: { + Authorization: "Bearer " + token, + }, + method: 'GET', + url: attachmentURL, + }).then(function (res) { + var attachmentPayload = JSON.parse(res); + var fetchedAttachment = payload_deserializer_1.default.createFetchedAttachmentFromPayload(attachmentPayload); + return fetchedAttachment; + }); + }); + }; + CurrentUser.prototype.isDataAttachment = function (attachment) { + return (attachment.file !== undefined && + attachment.name !== undefined); + }; + CurrentUser.prototype.isLinkAttachment = function (attachment) { + return (attachment.link !== undefined && + attachment.type !== undefined); + }; + CurrentUser.prototype.uploadFile = function (file, fileName, roomId) { + var data = new FormData(); + data.append('file', file, fileName); + return this.filesInstance + .request({ + body: data, + method: 'POST', + path: "/rooms/" + roomId + "/files/" + fileName, + }) + .then(function (res) { + return JSON.parse(res); + }); + }; + CurrentUser.prototype.sendMessageWithCompleteOptions = function (options, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + json: options, + method: 'POST', + path: "/rooms/" + options.roomId + "/messages", + }) + .then(function (res) { + var messageIdPayload = JSON.parse(res); + var messageId = messageIdPayload.message_id; + onSuccess(messageId); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error sending message to room " + options.roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.subscribeToCursors = function (room, roomDelegate) { + var _this = this; + room.cursorSubscription = new cursor_subscription_1.default({ + delegate: roomDelegate, + handleCursorSetInternal: function (cursor) { + if (cursor.userId === _this.id && _this.cursors !== undefined) { + _this.cursors[cursor.roomId] = cursor; + } + }, + logger: this.cursorsInstance.logger, + room: room, + userStore: this.userStore, + }); + this.cursorsInstance.subscribeNonResuming({ + listeners: { + onEvent: room.cursorSubscription.handleEvent.bind(room.cursorSubscription), + }, + path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id, + }); + }; + CurrentUser.prototype.getRooms = function (path, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: path, + }) + .then(function (res) { + var roomsPayload = JSON.parse(res); + var rooms = roomsPayload.map(function (roomPayload) { + return payload_deserializer_1.default.createRoomFromPayload(roomPayload); + }); + onSuccess(rooms); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error when getting instance rooms:', error); + onError(error); + }); + }; + return CurrentUser; +}()); +exports.default = CurrentUser; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var BasicMessageEnricher = (function () { + function BasicMessageEnricher(userStore, room, logger) { + this.completionOrderList = []; + this.messageIdToCompletionHandlers = {}; + this.enrichedMessagesAwaitingCompletionCalls = {}; + this.userIdsBeingRetrieved = []; + this.userIdsToBasicMessageIds = {}; + this.messagesAwaitingEnrichmentDependentOnUserRetrieval = {}; + this.userStore = userStore; + this.room = room; + this.logger = logger; + } + BasicMessageEnricher.prototype.enrich = function (basicMessage, onSuccess, onError) { + var _this = this; + var basicMessageId = basicMessage.id; + var basicMessageSenderId = basicMessage.senderId; + this.completionOrderList.push(basicMessageId); + this.messageIdToCompletionHandlers[basicMessageId] = { + onError: onError, + onSuccess: onSuccess, + }; + if (this.userIdsToBasicMessageIds[basicMessageSenderId] === undefined) { + this.userIdsToBasicMessageIds[basicMessageSenderId] = [basicMessageId]; + } + else { + this.userIdsToBasicMessageIds[basicMessageSenderId].push(basicMessageId); + } + this.messagesAwaitingEnrichmentDependentOnUserRetrieval[basicMessageId] = basicMessage; + if (this.userIdsBeingRetrieved.indexOf(basicMessageSenderId) > -1) { + return; + } + else { + this.userIdsBeingRetrieved.push(basicMessageSenderId); + } + this.userStore.user(basicMessageSenderId, function (user) { + var basicMessageIds = _this.userIdsToBasicMessageIds[basicMessageSenderId]; + if (basicMessageIds === undefined) { + _this.logger.verbose("Fetched user information for user with id " + user.id + " but no messages needed information for this user"); + return; + } + var basicMessages = basicMessageIds + .map(function (bmId) { + return _this.messagesAwaitingEnrichmentDependentOnUserRetrieval[bmId]; + }) + .filter(function (el) { return el !== undefined; }); + _this.enrichMessagesWithUser(user, basicMessages); + var indexToRemove = _this.userIdsBeingRetrieved.indexOf(basicMessageSenderId); + if (indexToRemove > -1) { + _this.userIdsBeingRetrieved.splice(indexToRemove, 1); + } + }, function (error) { + _this.logger.debug("Unable to find user with id " + basicMessage.senderId + ", associated with message " + basicMessageId + ". Error:", error); + _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessageId, error); + }); + }; + BasicMessageEnricher.prototype.enrichMessagesWithUser = function (user, messages) { + var _this = this; + messages.forEach(function (basicMessage) { + var message = { + attachment: basicMessage.attachment, + createdAt: basicMessage.createdAt, + id: basicMessage.id, + room: _this.room, + sender: user, + text: basicMessage.text, + updatedAt: basicMessage.updatedAt, + }; + _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessage.id, message); + }); + }; + BasicMessageEnricher.prototype.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo = function (id, result) { + var nextIdToComplete = this.completionOrderList[0]; + if (nextIdToComplete === undefined) { + return; + } + this.enrichedMessagesAwaitingCompletionCalls[id] = result; + if (id !== nextIdToComplete) { + this.logger.verbose("Waiting to call completion handler for message id " + id + " as there are other older messages still to be enriched"); + return; + } + do { + var messageId = this.completionOrderList[0]; + var completionHandler = this.messageIdToCompletionHandlers[messageId]; + if (completionHandler === undefined) { + this.logger.verbose("Completion handler not stored for message id " + messageId); + return; + } + var res = this.enrichedMessagesAwaitingCompletionCalls[messageId]; + if (res === undefined) { + this.logger.verbose("Enrichment result not stored for message id " + messageId); + return; + } + if (res.sender !== undefined) { + completionHandler.onSuccess(res); + } + else { + completionHandler.onError(res); + } + this.completionOrderList.shift(); + delete this.messageIdToCompletionHandlers[messageId]; + delete this.enrichedMessagesAwaitingCompletionCalls[messageId]; + } while (this.completionOrderList[0] !== undefined && + this.enrichedMessagesAwaitingCompletionCalls[this.completionOrderList[0]] !== undefined); + }; + return BasicMessageEnricher; +}()); +exports.default = BasicMessageEnricher; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var CursorSubscription = (function () { + function CursorSubscription(options) { + this.delegate = options.delegate; + this.logger = options.logger; + this.room = options.room; + this.userStore = options.userStore; + this.handleCursorSetInternal = options.handleCursorSetInternal; + } + CursorSubscription.prototype.handleEvent = function (event) { + var _this = this; + if (!this.delegate || !this.delegate.cursorSet) { + return; + } + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + if (eventName !== 'cursor_set') { + this.logger.verbose("Cursor subscription received event with type " + eventName + ", when 'cursor_set' was expected"); + return; + } + this.logger.verbose("Received event name: " + eventName + ", and data: " + data); + var basicCursor = payload_deserializer_1.default.createBasicCursorFromPayload(data); + this.logger.verbose("Room received cursor for: " + basicCursor.userId); + this.handleCursorSetInternal(basicCursor); + this.enrich(basicCursor, function (cursor) { + if (_this.delegate && _this.delegate.cursorSet) { + _this.delegate.cursorSet(cursor); + } + }, function (error) { + _this.logger.debug('Error receiving cursor:', error); + }); + }; + CursorSubscription.prototype.enrich = function (basicCursor, onSuccess, onError) { + var _this = this; + this.userStore.user(basicCursor.userId, function (user) { + onSuccess({ + cursorType: basicCursor.cursorType, + position: basicCursor.position, + room: _this.room, + updatedAt: basicCursor.updatedAt, + user: user, + }); + }, function (error) { + _this.logger.debug("Unable to find user with id " + basicCursor.userId + ". Error:", error); + onError(error); + }); + }; + return CursorSubscription; +}()); +exports.default = CursorSubscription; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var CursorType; +(function (CursorType) { + CursorType[CursorType["Read"] = 0] = "Read"; +})(CursorType || (CursorType = {})); +exports.default = CursorType; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var PresenceSubscription = (function () { + function PresenceSubscription(options) { + this.apiInstance = options.apiInstance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.delegate = options.delegate; + } + PresenceSubscription.prototype.handleEvent = function (event) { + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + this.apiInstance.logger.verbose("Received event type: " + eventName + ", and data: " + data); + switch (eventName) { + case 'initial_state': + this.parseInitialStatePayload(eventName, data, this.userStore); + break; + case 'presence_update': + this.parsePresenceUpdatePayload(eventName, data, this.userStore); + break; + case 'join_room_presence_update': + this.parseJoinRoomPresenceUpdatePayload(eventName, data, this.userStore); + break; + default: + this.apiInstance.logger.verbose("Unsupported event type received: " + eventName + ", and data: " + data); + break; + } + }; + PresenceSubscription.prototype.end = function () { + }; + PresenceSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { + var _this = this; + var userStatesPayload = data.user_states; + if (userStatesPayload === undefined || + userStatesPayload.constructor !== Array) { + this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); + return; + } + var userStates = userStatesPayload + .map(function (userStatePayload) { + return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); + }) + .filter(function (el) { return el !== undefined; }); + if (userStates.length === 0) { + this.apiInstance.logger.verbose('No presence user states to process'); + return; + } + this.userStore.handleInitialPresencePayloads(userStates, function () { + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }); + }; + PresenceSubscription.prototype.parsePresenceUpdatePayload = function (eventName, data, userStore) { + var _this = this; + var presencePayload = payload_deserializer_1.default.createPresencePayloadFromPayload(data); + userStore.user(presencePayload.userId, function (user) { + user.updatePresenceInfoIfAppropriate(presencePayload); + switch (presencePayload.state.stringValue) { + case 'online': + if (_this.delegate && _this.delegate.userCameOnline) { + _this.delegate.userCameOnline(user); + } + _this.apiInstance.logger.verbose(user.id + " came online"); + break; + case 'offline': + if (_this.delegate && _this.delegate.userWentOffline) { + _this.delegate.userWentOffline(user); + } + _this.apiInstance.logger.verbose(user.id + " went offline"); + break; + case 'unknown': + _this.apiInstance.logger.verbose("Somehow the presence state of user " + user.id + " is unknown"); + break; + } + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + return; + } + if (room.userIds.indexOf(user.id) > -1) { + switch (presencePayload.state.stringValue) { + case 'online': + if (room.subscription.delegate && + room.subscription.delegate.userCameOnlineInRoom) { + room.subscription.delegate.userCameOnlineInRoom(user); + } + break; + case 'offline': + if (room.subscription.delegate && + room.subscription.delegate.userWentOfflineInRoom) { + room.subscription.delegate.userWentOfflineInRoom(user); + } + break; + default: + break; + } + } + }); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching user information for user with id " + presencePayload.userId + ":", error); + return; + }); + }; + PresenceSubscription.prototype.parseJoinRoomPresenceUpdatePayload = function (eventName, data, userStore) { + var _this = this; + var userStatesPayload = data.user_states; + if (userStatesPayload === undefined || + userStatesPayload.constructor !== Array) { + this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); + return; + } + var userStates = userStatesPayload + .map(function (userStatePayload) { + return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); + }) + .filter(function (el) { return el !== undefined; }); + if (userStates.length === 0) { + this.apiInstance.logger.verbose('No presence user states to process'); + return; + } + this.userStore.handleInitialPresencePayloads(userStates, function () { + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }); + }; + return PresenceSubscription; +}()); +exports.default = PresenceSubscription; + + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var RoomStore = (function () { + function RoomStore(options) { + this.rooms = options.rooms; + this.apiInstance = options.apiInstance; + } + RoomStore.prototype.room = function (id, onSuccess, onError) { + this.findOrGetRoom(id, onSuccess, onError); + }; + RoomStore.prototype.addOrMerge = function (room) { + var existingRoom = this.rooms.find(function (el) { return el.id === room.id; }); + if (existingRoom) { + existingRoom.updateWithPropertiesOfRoom(room); + return existingRoom; + } + else { + this.rooms.push(room); + return room; + } + }; + RoomStore.prototype.remove = function (id) { + var indexOfRoom = this.rooms.findIndex(function (el) { return el.id === id; }); + if (indexOfRoom === -1) { + return undefined; + } + var room = this.rooms[indexOfRoom]; + this.rooms.splice(indexOfRoom, 1); + return room; + }; + RoomStore.prototype.findOrGetRoom = function (id, onSuccess, onError) { + var room = this.rooms.find(function (el) { return el.id === id; }); + if (room) { + onSuccess(room); + } + else { + this.getRoom(id, onSuccess, onError); + } + }; + RoomStore.prototype.getRoom = function (id, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: "/rooms/" + id, + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + onSuccess(room); + }) + .catch(function (error) { + _this.apiInstance.logger.debug("Error fetching room " + id + ":", error); + onError(error); + }); + }; + return RoomStore; +}()); +exports.default = RoomStore; + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var RoomSubscription = (function () { + function RoomSubscription(options) { + this.delegate = options.delegate; + this.basicMessageEnricher = options.basicMessageEnricher; + this.logger = options.logger; + } + RoomSubscription.prototype.handleEvent = function (event) { + var _this = this; + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + if (eventName !== 'new_message') { + this.logger.verbose("Room subscription received event with type " + eventName + ", when 'new_message' was expected"); + return; + } + this.logger.verbose("Received event name: " + eventName + ", and data:", data); + var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(data); + this.basicMessageEnricher.enrich(basicMessage, function (message) { + _this.logger.verbose("Room received new message: " + message.text); + if (_this.delegate && _this.delegate.newMessage) { + _this.delegate.newMessage(message); + } + }, function (error) { + _this.logger.debug('Error receiving new message:', error); + }); + }; + return RoomSubscription; +}()); +exports.default = RoomSubscription; + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var room_user_store_1 = __webpack_require__(19); +var Room = (function () { + function Room(options) { + this.id = options.id; + this.name = options.name; + this.isPrivate = options.isPrivate; + this.createdByUserId = options.createdByUserId; + this.createdAt = options.createdAt; + this.updatedAt = options.updatedAt; + this.deletedAt = options.deletedAt; + this.userIds = options.userIds || []; + this.userStore = new room_user_store_1.default(); + } + Room.prototype.updateWithPropertiesOfRoom = function (room) { + this.name = room.name; + this.isPrivate = room.isPrivate; + this.updatedAt = room.updatedAt; + this.deletedAt = room.deletedAt; + this.userIds = room.userIds; + }; + return Room; +}()); +exports.default = Room; + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var user_store_core_1 = __webpack_require__(5); +var RoomUserStore = (function () { + function RoomUserStore(userStoreCore) { + if (userStoreCore === void 0) { userStoreCore = new user_store_core_1.default(); } + this.userStoreCore = userStoreCore; + } + RoomUserStore.prototype.addOrMerge = function (user) { + return this.userStoreCore.addOrMerge(user); + }; + RoomUserStore.prototype.remove = function (id) { + return this.userStoreCore.remove(id); + }; + return RoomUserStore; +}()); +exports.default = RoomUserStore; + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var presence_state_1 = __webpack_require__(4); +var User = (function () { + function User(options) { + this.id = options.id; + this.createdAt = options.createdAt; + this.updatedAt = options.updatedAt; + this.name = options.name; + this.avatarURL = options.avatarURL; + this.customData = options.customData; + this.presenceState = new presence_state_1.default('unknown'); + } + User.prototype.updateWithPropertiesOfUser = function (user) { + if (user.presenceState.stringValue !== 'unknown') { + this.presenceState = user.presenceState; + this.lastSeenAt = user.lastSeenAt; + } + return this; + }; + User.prototype.updatePresenceInfoIfAppropriate = function (newInfoPayload) { + if (newInfoPayload.state.stringValue !== 'unknown') { + this.presenceState = newInfoPayload.state; + this.lastSeenAt = newInfoPayload.lastSeenAt; + } + }; + return User; +}()); +exports.default = User; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var constants_1 = __webpack_require__(3); +var utils_1 = __webpack_require__(1); +var UserSubscription = (function () { + function UserSubscription(options) { + this.typingTimers = {}; + this.apiInstance = options.apiInstance; + this.filesInstance = options.filesInstance; + this.cursorsInstance = options.cursorsInstance; + this.userStore = options.userStore; + this.delegate = options.delegate; + this.connectCompletionHandlers = [options.connectCompletionHandler]; + } + UserSubscription.prototype.handleEvent = function (event) { + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + this.apiInstance.logger.verbose("Received event name: " + eventName + ", and data: " + data); + switch (eventName) { + case 'initial_state': + this.parseInitialStatePayload(eventName, data, this.userStore); + break; + case 'added_to_room': + this.parseAddedToRoomPayload(eventName, data); + break; + case 'removed_from_room': + this.parseRemovedFromRoomPayload(eventName, data); + break; + case 'room_updated': + this.parseRoomUpdatedPayload(eventName, data); + break; + case 'room_deleted': + this.parseRoomDeletedPayload(eventName, data); + break; + case 'user_joined': + this.parseUserJoinedPayload(eventName, data); + break; + case 'user_left': + this.parseUserLeftPayload(eventName, data); + break; + case 'typing_start': + this.parseIsTypingPayload(eventName, data, data.user_id); + break; + case 'typing_stop': + break; + } + }; + UserSubscription.prototype.callConnectCompletionHandlers = function (currentUser, error) { + this.connectCompletionHandlers.forEach(function (completionHandler) { + completionHandler(currentUser, error); + }); + }; + UserSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { + var _this = this; + var roomsPayload = data.rooms; + var userPayload = data.current_user; + var receivedCurrentUser = payload_deserializer_1.default.createCurrentUserFromPayload(userPayload, this.apiInstance, this.filesInstance, this.cursorsInstance, this.userStore); + var wasExistingCurrentUser = this.currentUser !== undefined; + if (this.currentUser) { + this.currentUser.updateWithPropertiesOf(receivedCurrentUser); + } + else { + this.currentUser = receivedCurrentUser; + } + var receivedRoomsConstructor = roomsPayload.constructor; + if (receivedRoomsConstructor !== Array) { + throw TypeError('`rooms` key of initial_state payload was of type `${receivedRoomsConstructor}`, expected `Array`'); + } + if (roomsPayload.length === 0) { + this.currentUser.setupPresenceSubscription(this.delegate); + this.callConnectCompletionHandlers(this.currentUser); + return; + } + var combinedRoomUserIds = new Set([]); + var roomsFromConnection = []; + roomsPayload.forEach(function (roomPayload) { + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + room.userIds.forEach(function (userId) { + combinedRoomUserIds.add(userId); + }); + roomsFromConnection.push(room); + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.roomStore.addOrMerge(room); + }); + this.callConnectCompletionHandlers(this.currentUser); + this.fetchInitialUserInformationForUserIds(combinedRoomUserIds, this.currentUser); + if (wasExistingCurrentUser) { + this.reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection); + } + }; + UserSubscription.prototype.fetchInitialUserInformationForUserIds = function (userIds, currentUser) { + var _this = this; + var userIdsArray = Array.from(userIds.values()); + this.userStore.initialFetchOfUsersWithIds(userIdsArray, function (users) { + var combinedRoomUsersPromises = new Array(); + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.roomStore.rooms.forEach(function (room) { + var roomPromise = new Promise(function (roomResolve, roomReject) { + var roomUsersPromises = new Array(); + room.userIds.forEach(function (userId) { + var userPromise = new Promise(function (userResolve, userReject) { + _this.userStore.user(userId, function (user) { + room.userStore.addOrMerge(user); + userResolve(); + }, function (error) { + _this.apiInstance.logger.verbose("Unable to fetch information about user " + userId); + userReject(); + }); + }); + roomUsersPromises.push(userPromise); + }); + utils_1.allPromisesSettled(roomUsersPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name + "\""); + roomResolve(); + }); + }); + combinedRoomUsersPromises.push(roomPromise); + }); + utils_1.allPromisesSettled(combinedRoomUsersPromises).then(function () { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.setupPresenceSubscription(_this.delegate); + }); + }, function (error) { + _this.apiInstance.logger.debug("Unable to fetch user information after successful connection: " + error); + return; + }); + }; + UserSubscription.prototype.reconcileExistingRoomStoreWithRoomsReceivedOnConnection = function (roomsFromConnection) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property of UserSubscription unset after successful connection'); + return; + } + var roomStoreRooms = this.currentUser.roomStore.rooms; + var mostRecentConnectionRoomsSet = new Set(roomsFromConnection); + var noLongerAMemberOfRooms = roomStoreRooms.filter(function (room) { return !mostRecentConnectionRoomsSet.has(room); }); + noLongerAMemberOfRooms.forEach(function (room) { + if (_this.delegate && _this.delegate.removedFromRoom) { + _this.delegate.removedFromRoom(room); + } + }); + }; + UserSubscription.prototype.parseAddedToRoomPayload = function (eventName, data) { + var _this = this; + var roomPayload = data.room; + if (roomPayload === undefined || typeof roomPayload !== 'object') { + this.apiInstance.logger.verbose("`room` key missing or invalid in `added_to_room` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var roomAdded = this.currentUser.roomStore.addOrMerge(room); + if (this.delegate && this.delegate.addedToRoom) { + this.delegate.addedToRoom(room); + } + this.apiInstance.logger.verbose("Added to room: " + room.name); + var roomUsersPromises = new Array(); + roomAdded.userIds.forEach(function (userId) { + var userPromise = new Promise(function (resolve, reject) { + _this.userStore.user(userId, function (user) { + _this.apiInstance.logger.verbose("Added user id " + userId + " to room " + room.name); + room.userStore.addOrMerge(user); + resolve(); + }, function (error) { + _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room " + room.name + ": " + error); + reject(); + }); + }); + roomUsersPromises.push(userPromise); + }); + utils_1.allPromisesSettled(roomUsersPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }; + UserSubscription.prototype.parseRemovedFromRoomPayload = function (eventName, data) { + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `removed_from_room` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var roomRemoved = this.currentUser.roomStore.remove(roomId); + if (roomRemoved) { + if (this.delegate && this.delegate.removedFromRoom) { + this.delegate.removedFromRoom(roomRemoved); + } + this.apiInstance.logger.verbose("Removed from room: " + roomRemoved.name); + } + else { + this.apiInstance.logger.verbose("Received `removed_from_room` API event but room with ID " + roomId + " not found in local store of joined rooms"); + return; + } + }; + UserSubscription.prototype.parseRoomUpdatedPayload = function (eventName, data) { + var _this = this; + var roomPayload = data.room; + if (roomPayload === undefined || typeof roomPayload !== 'object') { + this.apiInstance.logger.verbose("`room` key missing or invalid in `room_updated` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + this.currentUser.roomStore.room(room.id, function (roomToUpdate) { + roomToUpdate.updateWithPropertiesOfRoom(room); + if (_this.delegate && _this.delegate.roomUpdated) { + _this.delegate.roomUpdated(roomToUpdate); + } + _this.apiInstance.logger.verbose("Room updated: " + room.name); + }, function (error) { + _this.apiInstance.logger.debug("Error updating room " + room.id + ":", error); + }); + }; + UserSubscription.prototype.parseRoomDeletedPayload = function (eventName, data) { + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `room_deleted` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var deletedRoom = this.currentUser.roomStore.remove(roomId); + if (deletedRoom) { + if (this.delegate && this.delegate.roomDeleted) { + this.delegate.roomDeleted(deletedRoom); + } + this.apiInstance.logger.verbose("Room deleted: " + deletedRoom.name); + } + else { + this.apiInstance.logger.verbose("Received `room_deleted` API event but room with ID " + roomId + " not found in local store of joined rooms"); + return; + } + }; + UserSubscription.prototype.parseUserJoinedPayload = function (eventName, data) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_joined` payload: " + data); + return; + } + var userId = data.user_id; + if (userId === undefined || typeof userId !== 'string') { + this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_joined` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + var addedOrMergedUser = room.userStore.addOrMerge(user); + if (room.userIds.indexOf(addedOrMergedUser.id) === -1) { + room.userIds.push(addedOrMergedUser.id); + } + if (_this.delegate && _this.delegate.userJoinedRoom) { + _this.delegate.userJoinedRoom(room, addedOrMergedUser); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userJoined) { + room.subscription.delegate.userJoined(addedOrMergedUser); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " joined room: " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); + return; + }); + }; + UserSubscription.prototype.parseUserLeftPayload = function (eventName, data) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_left` payload: " + data); + return; + } + var userId = data.user_id; + if (userId === undefined || typeof userId !== 'string') { + this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_left` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + var roomUserIdIndex = room.userIds.indexOf(user.id); + if (roomUserIdIndex > -1) { + room.userIds.splice(roomUserIdIndex, 1); + } + room.userStore.remove(user.id); + if (_this.delegate && _this.delegate.userLeftRoom) { + _this.delegate.userLeftRoom(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userLeft) { + room.subscription.delegate.userLeft(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " left room " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " left room with id " + roomId + " but no information about the user could be retrieved. Error was: " + error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); + return; + }); + }; + UserSubscription.prototype.parseIsTypingPayload = function (eventName, data, userId) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `typing_start` payload: " + data); + return; + } + if (!this.typingTimers[roomId]) { + this.typingTimers[roomId] = {}; + } + if (this.typingTimers[roomId][userId]) { + clearTimeout(this.typingTimers[roomId][userId]); + } + else { + this.startedTyping(roomId, userId); + } + this.typingTimers[roomId][userId] = setTimeout(function () { + _this.stoppedTyping(roomId, userId); + delete _this.typingTimers[roomId][userId]; + }, constants_1.TYPING_REQ_TTL); + }; + UserSubscription.prototype.startedTyping = function (roomId, userId) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + if (_this.delegate && _this.delegate.userStartedTyping) { + _this.delegate.userStartedTyping(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userStartedTyping) { + room.subscription.delegate.userStartedTyping(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " started typing in room " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching information for user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching information for room " + roomId + ":", error); + return; + }); + }; + UserSubscription.prototype.stoppedTyping = function (roomId, userId) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + if (_this.delegate && _this.delegate.userStoppedTyping) { + _this.delegate.userStoppedTyping(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userStoppedTyping) { + room.subscription.delegate.userStoppedTyping(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " stopped typing in room " + room.name); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching information for user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching information for room " + roomId + ":", error); + return; + }); + }; + return UserSubscription; +}()); +exports.default = UserSubscription; + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/dist/react-native/declarations/attachment.d.ts b/dist/react-native/declarations/attachment.d.ts new file mode 100644 index 0000000..1e89409 --- /dev/null +++ b/dist/react-native/declarations/attachment.d.ts @@ -0,0 +1,6 @@ +interface Attachment { + fetchRequired: boolean; + link: string; + type: string; +} +export default Attachment; diff --git a/dist/react-native/declarations/basic_cursor.d.ts b/dist/react-native/declarations/basic_cursor.d.ts new file mode 100644 index 0000000..1ab80b5 --- /dev/null +++ b/dist/react-native/declarations/basic_cursor.d.ts @@ -0,0 +1,8 @@ +interface BasicCursor { + cursorType: number; + position: number; + roomId: number; + updatedAt: string; + userId: string; +} +export default BasicCursor; diff --git a/dist/react-native/declarations/basic_message.d.ts b/dist/react-native/declarations/basic_message.d.ts new file mode 100644 index 0000000..b28e155 --- /dev/null +++ b/dist/react-native/declarations/basic_message.d.ts @@ -0,0 +1,11 @@ +import Attachment from './attachment'; +interface BasicMessage { + id: number; + senderId: string; + roomId: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; +} +export default BasicMessage; diff --git a/dist/react-native/declarations/basic_message_enricher.d.ts b/dist/react-native/declarations/basic_message_enricher.d.ts new file mode 100644 index 0000000..a8f7e15 --- /dev/null +++ b/dist/react-native/declarations/basic_message_enricher.d.ts @@ -0,0 +1,38 @@ +import { Logger } from 'pusher-platform'; +import BasicMessage from './basic_message'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import Room from './room'; +import User from './user'; +export interface MessageEnrichmentCompletionHandlers { + onSuccess: (message: Message) => void; + onError: (error: any) => void; +} +export declare type MessageIdsToCompletionHandlers = { + [key: number]: MessageEnrichmentCompletionHandlers; +}; +export declare type UserIdsToBasicMessageIds = { + [key: string]: number[]; +}; +export declare type MessageEnrichmentResult = Message | any; +export declare type MessageIdsToEnrichmentResults = { + [key: number]: MessageEnrichmentResult; +}; +export declare type MessageIdsToBasicMessages = { + [key: number]: BasicMessage; +}; +export default class BasicMessageEnricher { + userStore: GlobalUserStore; + room: Room; + logger: Logger; + private completionOrderList; + private messageIdToCompletionHandlers; + private enrichedMessagesAwaitingCompletionCalls; + private userIdsBeingRetrieved; + private userIdsToBasicMessageIds; + private messagesAwaitingEnrichmentDependentOnUserRetrieval; + constructor(userStore: GlobalUserStore, room: Room, logger: Logger); + enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; + enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; + callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; +} diff --git a/dist/react-native/declarations/basic_user.d.ts b/dist/react-native/declarations/basic_user.d.ts new file mode 100644 index 0000000..fb90490 --- /dev/null +++ b/dist/react-native/declarations/basic_user.d.ts @@ -0,0 +1,6 @@ +interface BasicUser { + id: string; + createdAt: string; + updatedAt: string; +} +export default BasicUser; diff --git a/dist/react-native/declarations/chat_manager.d.ts b/dist/react-native/declarations/chat_manager.d.ts new file mode 100644 index 0000000..49a8817 --- /dev/null +++ b/dist/react-native/declarations/chat_manager.d.ts @@ -0,0 +1,25 @@ +import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +export interface ChatManagerOptions { + instanceLocator: string; + tokenProvider: TokenProvider; + logger?: Logger; + baseClient?: BaseClient; + userId: string; +} +export default class ChatManager { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userId: string; + private userStore; + private userSubscription; + constructor(options: ChatManagerOptions); + connect(options: ConnectOptions): void; +} +export interface ConnectOptions { + delegate?: ChatManagerDelegate; + onSuccess: (currentUser: CurrentUser) => void; + onError: (error: any) => void; +} diff --git a/dist/react-native/declarations/chat_manager_delegate.d.ts b/dist/react-native/declarations/chat_manager_delegate.d.ts new file mode 100644 index 0000000..5b2d790 --- /dev/null +++ b/dist/react-native/declarations/chat_manager_delegate.d.ts @@ -0,0 +1,16 @@ +import Room from './room'; +import User from './user'; +interface ChatManagerDelegate { + addedToRoom?: (room: Room) => void; + removedFromRoom?: (room: Room) => void; + roomUpdated?: (room: Room) => void; + roomDeleted?: (room: Room) => void; + userStartedTyping?: (room: Room, user: User) => void; + userStoppedTyping?: (room: Room, user: User) => void; + userJoinedRoom?: (room: Room, user: User) => void; + userLeftRoom?: (room: Room, user: User) => void; + userCameOnline?: (user: User) => void; + userWentOffline?: (user: User) => void; + error?: (error: any) => void; +} +export default ChatManagerDelegate; diff --git a/dist/react-native/declarations/constants.d.ts b/dist/react-native/declarations/constants.d.ts new file mode 100644 index 0000000..d18fd38 --- /dev/null +++ b/dist/react-native/declarations/constants.d.ts @@ -0,0 +1,2 @@ +export declare const TYPING_REQ_TTL = 1500; +export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/react-native/declarations/current_user.d.ts b/dist/react-native/declarations/current_user.d.ts new file mode 100644 index 0000000..77a8eae --- /dev/null +++ b/dist/react-native/declarations/current_user.d.ts @@ -0,0 +1,111 @@ +import { Instance } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import PresenceSubscription from './presence_subscription'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +import RoomStore from './room_store'; +export interface CreateRoomOptions { + name: string; + private?: boolean; + addUserIds?: string[]; +} +export interface UpdateRoomOptions { + name?: string; + isPrivate?: boolean; +} +export interface FetchRoomMessagesOptions { + initialId?: string; + limit?: number; + direction?: string; +} +export interface CurrentUserOptions { + id: string; + createdAt: string; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + rooms?: Room[]; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; +} +export interface DataAttachment { + file: Blob; + name: string; +} +export interface LinkAttachment { + link: string; + type: string; +} +export declare type GenericAttachment = LinkAttachment | DataAttachment; +export interface AttachmentBody { + resource_link: string; + type: string; +} +export interface SendMessageOptions { + attachment?: GenericAttachment; + roomId: number; + text?: string; +} +export interface CompleteMessageOptions { + attachment?: AttachmentBody; + roomId: number; + text?: string; + user_id: string; +} +export default class CurrentUser { + id: string; + createdAt: string; + cursors: { + [roomId: string]: BasicCursor; + }; + cursorsReq: Promise; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + userStore: GlobalUserStore; + roomStore: RoomStore; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + pathFriendlyId: string; + presenceSubscription: PresenceSubscription; + typingRequestSent: { + [roomId: string]: number; + }; + readonly rooms: Room[]; + constructor(options: CurrentUserOptions); + updateWithPropertiesOf(currentUser: CurrentUser): void; + setupPresenceSubscription(delegate?: ChatManagerDelegate): void; + createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + populateRoomUserStore(room: Room): void; + addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; + deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; + joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; + sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; + subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; + fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; + fetchAttachment(attachmentURL: string): Promise; + private isDataAttachment(attachment); + private isLinkAttachment(attachment); + private uploadFile(file, fileName, roomId); + private sendMessageWithCompleteOptions(options, onSuccess, onError); + private subscribeToCursors(room, roomDelegate); + private getRooms(path, onSuccess, onError); +} diff --git a/dist/react-native/declarations/cursor.d.ts b/dist/react-native/declarations/cursor.d.ts new file mode 100644 index 0000000..3aa3524 --- /dev/null +++ b/dist/react-native/declarations/cursor.d.ts @@ -0,0 +1,10 @@ +import Room from './room'; +import User from './user'; +interface Cursor { + cursorType: number; + position: number; + room: Room; + updatedAt: string; + user: User; +} +export default Cursor; diff --git a/dist/react-native/declarations/cursor_subscription.d.ts b/dist/react-native/declarations/cursor_subscription.d.ts new file mode 100644 index 0000000..08e991b --- /dev/null +++ b/dist/react-native/declarations/cursor_subscription.d.ts @@ -0,0 +1,23 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import Cursor from './cursor'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +export interface CursorSubscriptionOptions { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; +} +export default class CursorSubscription { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; + constructor(options: CursorSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; +} diff --git a/dist/react-native/declarations/cursor_types.d.ts b/dist/react-native/declarations/cursor_types.d.ts new file mode 100644 index 0000000..01f22f7 --- /dev/null +++ b/dist/react-native/declarations/cursor_types.d.ts @@ -0,0 +1,4 @@ +declare enum CursorType { + Read = 0, +} +export default CursorType; diff --git a/dist/react-native/declarations/fetched_attachment.d.ts b/dist/react-native/declarations/fetched_attachment.d.ts new file mode 100644 index 0000000..907eddc --- /dev/null +++ b/dist/react-native/declarations/fetched_attachment.d.ts @@ -0,0 +1,11 @@ +export interface FetchedAttachmentFile { + bytes: number; + lastModified: number; + name: string; +} +interface FetchedAttachment { + file: FetchedAttachmentFile; + link: string; + ttl: number; +} +export default FetchedAttachment; diff --git a/dist/react-native/declarations/global_user_store.d.ts b/dist/react-native/declarations/global_user_store.d.ts new file mode 100644 index 0000000..7712fe4 --- /dev/null +++ b/dist/react-native/declarations/global_user_store.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import PresencePayload from './presence_payload'; +import User from './user'; +import UserStoreCore from './user_store_core'; +export interface GlobalUserStoreOptions { + apiInstance: Instance; + userStoreCore?: UserStoreCore; +} +export default class GlobalUserStore { + private apiInstance; + private userStoreCore; + constructor(options: GlobalUserStoreOptions); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; + handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; + fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; + initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; +} diff --git a/dist/react-native/declarations/index.d.ts b/dist/react-native/declarations/index.d.ts new file mode 100644 index 0000000..8118af7 --- /dev/null +++ b/dist/react-native/declarations/index.d.ts @@ -0,0 +1,10 @@ +import { BaseClient } from 'pusher-platform'; +import ChatManager from './chat_manager'; +import TokenProvider from './token_provider'; +export { BaseClient, ChatManager, TokenProvider }; +declare const _default: { + BaseClient: typeof BaseClient; + ChatManager: typeof ChatManager; + TokenProvider: typeof TokenProvider; +}; +export default _default; diff --git a/dist/react-native/declarations/message.d.ts b/dist/react-native/declarations/message.d.ts new file mode 100644 index 0000000..d7bd58d --- /dev/null +++ b/dist/react-native/declarations/message.d.ts @@ -0,0 +1,13 @@ +import Attachment from './attachment'; +import Room from './room'; +import User from './user'; +interface Message { + id: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; + sender: User; + room: Room; +} +export default Message; diff --git a/dist/react-native/declarations/payload_deserializer.d.ts b/dist/react-native/declarations/payload_deserializer.d.ts new file mode 100644 index 0000000..bb635f2 --- /dev/null +++ b/dist/react-native/declarations/payload_deserializer.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import Attachment from './attachment'; +import BasicCursor from './basic_cursor'; +import BasicMessage from './basic_message'; +import BasicUser from './basic_user'; +import CurrentUser from './current_user'; +import FetchedAttachment from './fetched_attachment'; +import GlobalUserStore from './global_user_store'; +import PresencePayload from './presence_payload'; +import Room from './room'; +import User from './user'; +export default class PayloadDeserializer { + static createUserFromPayload(userPayload: any): User; + static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; + static createRoomFromPayload(roomPayload: any): Room; + static createBasicMessageFromPayload(messagePayload: any): BasicMessage; + static createBasicCursorFromPayload(payload: any): BasicCursor; + static createPresencePayloadFromPayload(payload: any): PresencePayload; + static createBasicUserFromPayload(payload: any): BasicUser; + static createAttachmentFromPayload(payload: any): Attachment | undefined; + static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; +} diff --git a/dist/react-native/declarations/presence_payload.d.ts b/dist/react-native/declarations/presence_payload.d.ts new file mode 100644 index 0000000..c2a2215 --- /dev/null +++ b/dist/react-native/declarations/presence_payload.d.ts @@ -0,0 +1,7 @@ +import PresenceState from './presence_state'; +interface PresencePayload { + userId: string; + state: PresenceState; + lastSeenAt?: string; +} +export default PresencePayload; diff --git a/dist/react-native/declarations/presence_state.d.ts b/dist/react-native/declarations/presence_state.d.ts new file mode 100644 index 0000000..b7bd7d0 --- /dev/null +++ b/dist/react-native/declarations/presence_state.d.ts @@ -0,0 +1,4 @@ +export default class PresenceState { + stringValue: string; + constructor(state: string); +} diff --git a/dist/react-native/declarations/presence_subscription.d.ts b/dist/react-native/declarations/presence_subscription.d.ts new file mode 100644 index 0000000..53583cc --- /dev/null +++ b/dist/react-native/declarations/presence_subscription.d.ts @@ -0,0 +1,22 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import RoomStore from './room_store'; +export interface PresenceSubscriptionOptions { + apiInstance: Instance; + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; +} +export default class PresenceSubscription { + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; + private apiInstance; + constructor(options: PresenceSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + end(): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; +} diff --git a/dist/react-native/declarations/room.d.ts b/dist/react-native/declarations/room.d.ts new file mode 100644 index 0000000..f62e355 --- /dev/null +++ b/dist/react-native/declarations/room.d.ts @@ -0,0 +1,28 @@ +import CursorSubscription from './cursor_subscription'; +import RoomSubscription from './room_subscription'; +import RoomUserStore from './room_user_store'; +export interface RoomOptions { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds?: string[]; +} +export default class Room { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds: string[]; + userStore: RoomUserStore; + subscription?: RoomSubscription; + cursorSubscription?: CursorSubscription; + constructor(options: RoomOptions); + updateWithPropertiesOfRoom(room: Room): void; +} diff --git a/dist/react-native/declarations/room_delegate.d.ts b/dist/react-native/declarations/room_delegate.d.ts new file mode 100644 index 0000000..fbfb142 --- /dev/null +++ b/dist/react-native/declarations/room_delegate.d.ts @@ -0,0 +1,16 @@ +import Cursor from './cursor'; +import Message from './message'; +import User from './user'; +interface RoomDelegate { + newMessage?: (message: Message) => void; + userStartedTyping?: (user: User) => void; + userStoppedTyping?: (user: User) => void; + userJoined?: (user: User) => void; + userLeft?: (user: User) => void; + userCameOnlineInRoom?: (user: User) => void; + userWentOfflineInRoom?: (user: User) => void; + usersUpdated?: () => void; + error?: (error: any) => void; + cursorSet?: (cursor: Cursor) => void; +} +export default RoomDelegate; diff --git a/dist/react-native/declarations/room_store.d.ts b/dist/react-native/declarations/room_store.d.ts new file mode 100644 index 0000000..9d9befa --- /dev/null +++ b/dist/react-native/declarations/room_store.d.ts @@ -0,0 +1,16 @@ +import { Instance } from 'pusher-platform'; +import Room from './room'; +export interface RoomStoreOptions { + rooms: Room[]; + apiInstance: Instance; +} +export default class RoomStore { + rooms: Room[]; + apiInstance: Instance; + constructor(options: RoomStoreOptions); + room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + addOrMerge(room: Room): Room; + remove(id: number): Room | undefined; + findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; +} diff --git a/dist/react-native/declarations/room_subscription.d.ts b/dist/react-native/declarations/room_subscription.d.ts new file mode 100644 index 0000000..c37121a --- /dev/null +++ b/dist/react-native/declarations/room_subscription.d.ts @@ -0,0 +1,15 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicMessageEnricher from './basic_message_enricher'; +import RoomDelegate from './room_delegate'; +export interface RoomSubscriptionOptions { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; +} +export default class RoomSubscription { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; + constructor(options: RoomSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; +} diff --git a/dist/react-native/declarations/room_user_store.d.ts b/dist/react-native/declarations/room_user_store.d.ts new file mode 100644 index 0000000..eb1f60f --- /dev/null +++ b/dist/react-native/declarations/room_user_store.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +import UserStoreCore from './user_store_core'; +export default class RoomUserStore { + private userStoreCore; + constructor(userStoreCore?: UserStoreCore); + addOrMerge(user: User): User; + remove(id: string): User | undefined; +} diff --git a/dist/react-native/declarations/token_provider.d.ts b/dist/react-native/declarations/token_provider.d.ts new file mode 100644 index 0000000..5fb85e9 --- /dev/null +++ b/dist/react-native/declarations/token_provider.d.ts @@ -0,0 +1,29 @@ +import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; +export interface TokenProviderAuthContextOptions { + queryParams?: TokenProviderAuthContextQueryParams; + headers?: TokenProviderAuthContextHeaders; +} +export declare type TokenProviderAuthContextHeaders = { + [key: string]: string; +}; +export declare type TokenProviderAuthContextQueryParams = { + [key: string]: string; +}; +export interface TokenProviderOptions { + authContext?: TokenProviderAuthContextOptions; + url: string; +} +export default class TokenProvider implements PlatformTokenProvider { + authContext?: TokenProviderAuthContextOptions; + url: string; + userId?: string; + cachedAccessToken?: string; + cachedTokenExpiresAt?: number; + constructor(options: TokenProviderOptions); + readonly cacheIsStale: boolean; + fetchToken(tokenParams?: any): Promise; + clearToken(token?: string): void; + makeAuthRequest(): Promise; + private cache(accessToken, expiresIn); + private unixTimeNow(); +} diff --git a/dist/react-native/declarations/user.d.ts b/dist/react-native/declarations/user.d.ts new file mode 100644 index 0000000..7e0b5f4 --- /dev/null +++ b/dist/react-native/declarations/user.d.ts @@ -0,0 +1,23 @@ +import PresencePayload from './presence_payload'; +import PresenceState from './presence_state'; +export interface UserOptions { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; +} +export default class User { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; + presenceState: PresenceState; + lastSeenAt?: string; + constructor(options: UserOptions); + updateWithPropertiesOfUser(user: User): this; + updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; +} diff --git a/dist/react-native/declarations/user_store_core.d.ts b/dist/react-native/declarations/user_store_core.d.ts new file mode 100644 index 0000000..a55ef61 --- /dev/null +++ b/dist/react-native/declarations/user_store_core.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +export default class UserStoreCore { + private users; + constructor(users?: User[]); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + find(id: string): User | undefined; +} diff --git a/dist/react-native/declarations/user_subscription.d.ts b/dist/react-native/declarations/user_subscription.d.ts new file mode 100644 index 0000000..42ea461 --- /dev/null +++ b/dist/react-native/declarations/user_subscription.d.ts @@ -0,0 +1,38 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +export interface UserSubscriptionOptions { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; +} +export default class UserSubscription { + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; + currentUser?: CurrentUser; + private apiInstance; + private filesInstance; + private cursorsInstance; + private typingTimers; + constructor(options: UserSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; + reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; + parseAddedToRoomPayload(eventName: string, data: any): void; + parseRemovedFromRoomPayload(eventName: string, data: any): void; + parseRoomUpdatedPayload(eventName: string, data: any): void; + parseRoomDeletedPayload(eventName: string, data: any): void; + parseUserJoinedPayload(eventName: string, data: any): void; + parseUserLeftPayload(eventName: string, data: any): void; + parseIsTypingPayload(eventName: string, data: any, userId: string): void; + private startedTyping(roomId, userId); + private stoppedTyping(roomId, userId); +} diff --git a/dist/react-native/declarations/utils.d.ts b/dist/react-native/declarations/utils.d.ts new file mode 100644 index 0000000..dbf28ce --- /dev/null +++ b/dist/react-native/declarations/utils.d.ts @@ -0,0 +1,5 @@ +export declare function urlEncode(data: any): string; +export declare function queryString(data: any): string; +export declare function queryParamsFromFullUrl(url: string): any; +export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; +export declare function allPromisesSettled(promises: Array>): Promise; diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js new file mode 100644 index 0000000..8125208 --- /dev/null +++ b/dist/web/chatkit.js @@ -0,0 +1,6697 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Chatkit = factory()); +}(this, (function () { 'use strict'; + +var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + + +function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var pusherPlatform = createCommonjsModule(function (module, exports) { +(function webpackUniversalModuleDefinition(root, factory) { + module.exports = factory(); +})(commonjsGlobal, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 10); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +function responseToHeadersObject(headerStr) { + var headers = {}; + if (!headerStr) { + return headers; + } + var headerPairs = headerStr.split('\u000d\u000a'); + for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { + var headerPair = headerPairs_1[_i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) { + var key = headerPair.substring(0, index); + var val = headerPair.substring(index + 2); + headers[key] = val; + } + } + return headers; +} +exports.responseToHeadersObject = responseToHeadersObject; +var ErrorResponse = (function () { + function ErrorResponse(statusCode, headers, info) { + this.statusCode = statusCode; + this.headers = headers; + this.info = info; + } + ErrorResponse.fromXHR = function (xhr) { + var errorInfo = xhr.responseText; + try { + errorInfo = JSON.parse(xhr.responseText); + } + catch (e) { + } + return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); + }; + return ErrorResponse; +}()); +exports.ErrorResponse = ErrorResponse; +var NetworkError = (function () { + function NetworkError(error) { + this.error = error; + } + return NetworkError; +}()); +exports.NetworkError = NetworkError; +var XhrReadyState; +(function (XhrReadyState) { + XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; + XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; + XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; + XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; + XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; +})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; + LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; + LogLevel[LogLevel["INFO"] = 3] = "INFO"; + LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; + LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; +})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); +var ConsoleLogger = (function () { + function ConsoleLogger(threshold) { + if (threshold === void 0) { threshold = 2; } + this.threshold = threshold; + var groups = Array(); + var hr = '--------------------------------------------------------------------------------'; + if (!window.console.group) { + window.console.group = function (label) { + groups.push(label); + window.console.log('%c \nBEGIN GROUP: %c', hr, label); + }; + } + if (!window.console.groupEnd) { + window.console.groupEnd = function () { + window.console.log('END GROUP: %c\n%c', groups.pop(), hr); + }; + } + } + ConsoleLogger.prototype.verbose = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.log, LogLevel.VERBOSE, items); + }; + ConsoleLogger.prototype.debug = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.log, LogLevel.DEBUG, items); + }; + ConsoleLogger.prototype.info = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.info, LogLevel.INFO, items); + }; + ConsoleLogger.prototype.warn = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.warn, LogLevel.WARNING, items); + }; + ConsoleLogger.prototype.error = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.error, LogLevel.ERROR, items); + }; + ConsoleLogger.prototype.log = function (logFunction, level, items) { + var _this = this; + if (level >= this.threshold) { + var loggerSignature_1 = "Logger." + LogLevel[level]; + if (items.length > 1) { + window.console.group(); + items.forEach(function (item) { + _this.errorAwareLog(logFunction, item, loggerSignature_1); + }); + window.console.groupEnd(); + } + else { + this.errorAwareLog(logFunction, items[0], loggerSignature_1); + } + } + }; + ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { + if (item.info && item.info.error_uri) { + var errorDesc = item.info.error_description; + var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; + logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); + } + else { + logFunction(loggerSignature + ": ", item); + } + }; + return ConsoleLogger; +}()); +exports.ConsoleLogger = ConsoleLogger; +var EmptyLogger = (function () { + function EmptyLogger() { + } + EmptyLogger.prototype.verbose = function (message, error) { }; + EmptyLogger.prototype.debug = function (message, error) { }; + EmptyLogger.prototype.info = function (message, error) { }; + EmptyLogger.prototype.warn = function (message, error) { }; + EmptyLogger.prototype.error = function (message, error) { }; + return EmptyLogger; +}()); +exports.EmptyLogger = EmptyLogger; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createRetryStrategyOptionsOrDefault = function (options) { + var initialTimeoutMillis = options.initialTimeoutMillis || 1000; + var maxTimeoutMillis = options.maxTimeoutMillis || 5000; + var limit = -1; + if (options.limit !== undefined && options.limit != null) { + limit = options.limit; + } + var increaseTimeout; + if (options.increaseTimeout !== undefined) { + increaseTimeout = options.increaseTimeout; + } + else { + increaseTimeout = function (currentTimeout) { + if (currentTimeout * 2 > maxTimeoutMillis) { + return maxTimeoutMillis; + } + else { + return currentTimeout * 2; + } + }; + } + return { + increaseTimeout: increaseTimeout, + initialTimeoutMillis: initialTimeoutMillis, + limit: limit, + maxTimeoutMillis: maxTimeoutMillis, + }; +}; +var Retry = (function () { + function Retry(waitTimeMillis) { + this.waitTimeMillis = waitTimeMillis; + } + return Retry; +}()); +exports.Retry = Retry; +var DoNotRetry = (function () { + function DoNotRetry(error) { + this.error = error; + } + return DoNotRetry; +}()); +exports.DoNotRetry = DoNotRetry; +var requestMethodIsSafe = function (method) { + method = method.toUpperCase(); + return (method === 'GET' || + method === 'HEAD' || + method === 'OPTIONS' || + method === 'SUBSCRIBE'); +}; +var RetryResolution = (function () { + function RetryResolution(options, logger, retryUnsafeRequests) { + this.options = options; + this.logger = logger; + this.retryUnsafeRequests = retryUnsafeRequests; + this.currentRetryCount = 0; + this.initialTimeoutMillis = options.initialTimeoutMillis; + this.maxTimeoutMillis = options.maxTimeoutMillis; + this.limit = options.limit; + this.increaseTimeoutFunction = options.increaseTimeout; + this.currentBackoffMillis = this.initialTimeoutMillis; + } + RetryResolution.prototype.attemptRetry = function (error) { + this.logger.verbose(this.constructor.name + ": Error received", error); + if (this.currentRetryCount >= this.limit && this.limit >= 0) { + this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); + return new DoNotRetry(error); + } + if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { + this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); + return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); + } + if (error instanceof network_1.NetworkError || + (error instanceof network_1.ErrorResponse && + requestMethodIsSafe(error.headers['Request-Method'])) || + this.retryUnsafeRequests) { + return this.shouldSafeRetry(error); + } + if (error instanceof network_1.NetworkError) { + return this.shouldSafeRetry(error); + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.shouldSafeRetry = function (error) { + if (error instanceof network_1.NetworkError) { + this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); + return new Retry(this.calulateMillisToRetry()); + } + else if (error instanceof network_1.ErrorResponse) { + if (error.statusCode >= 500 && error.statusCode < 600) { + this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); + return new Retry(this.calulateMillisToRetry()); + } + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.calulateMillisToRetry = function () { + this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); + this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); + return this.currentBackoffMillis; + }; + return RetryResolution; +}()); +exports.RetryResolution = RetryResolution; + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var logger_1 = __webpack_require__(1); +var request_1 = __webpack_require__(4); +var resuming_subscription_1 = __webpack_require__(5); +var retrying_subscription_1 = __webpack_require__(6); +var subscribe_strategy_1 = __webpack_require__(11); +var subscription_1 = __webpack_require__(12); +var token_providing_subscription_1 = __webpack_require__(7); +var http_1 = __webpack_require__(13); +var websocket_1 = __webpack_require__(14); +var transports_1 = __webpack_require__(8); +var BaseClient = (function () { + function BaseClient(options) { + this.options = options; + this.host = options.host.replace(/(\/)+$/, ''); + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.websocketTransport = new websocket_1.default(this.host); + this.httpTransport = new http_1.default(this.host, options.encrypted); + } + BaseClient.prototype.request = function (options, tokenParams) { + var _this = this; + if (options.tokenProvider) { + return options.tokenProvider + .fetchToken(tokenParams) + .then(function (token) { + if (options.headers !== undefined) { + options.headers['Authorization'] = "Bearer " + token; + } + else { + options.headers = (_a = {}, _a['Authorization'] = "Bearer " + token, _a); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + var _a; + }) + .catch(function (error) { + _this.logger.error(error); + }); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + }; + BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + return BaseClient; +}()); +exports.BaseClient = BaseClient; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +function executeNetworkRequest(createXhr, options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); + sendBody(xhr, options); + }); +} +exports.executeNetworkRequest = executeNetworkRequest; +function sendBody(xhr, options) { + if (options.json) { + xhr.send(JSON.stringify(options.json)); + } + else { + xhr.send(options.body); + } +} +function sendRawRequest(options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(new window.XMLHttpRequest(), resolve, reject); + xhr.open(options.method.toUpperCase(), options.url, true); + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + xhr.send(options.body); + }); +} +exports.sendRawRequest = sendRawRequest; +function attachOnReadyStateChangeHandler(xhr, resolve, reject) { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.response); + } + else if (xhr.status !== 0) { + reject(network_1.ErrorResponse.fromXHR(xhr)); + } + else { + reject(new network_1.NetworkError('No Connection')); + } + } + }; + return xhr; +} + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { + var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); + var ResumingSubscription = (function () { + function ResumingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + this.onTransition = onTransition; + var lastEventId = initialEventId; + logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); + if (lastEventId) { + headers['Last-Event-Id'] = lastEventId; + logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); + } + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpeningSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpenSubscriptionState; + }()); + var ResumingSubscriptionState = (function () { + function ResumingSubscriptionState(error, onTransition, lastEventId) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); + var executeSubscriptionOnce = function (error, lastEventId) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = window.setTimeout(function () { + executeNextSubscribeStrategy(lastEventId); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function (lastEventId) { + logger.verbose("ResumingSubscription: trying to re-establish the subscription"); + if (lastEventId) { + logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); + headers['Last-Event-Id'] = lastEventId; + } + _this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + executeSubscriptionOnce(error, lastEventId); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error, lastEventId); + } + ResumingSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + window.clearTimeout(this.timeout); + this.underlyingSubscription.unsubscribe(); + }; + return ResumingSubscriptionState; + }()); + var EndingSubscriptionState = (function () { + function EndingSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); + } + EndingSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription is already ending'); + }; + return EndingSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return ResumingSubscription; + }()); + return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { + var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); + var RetryingSubscription = (function () { + function RetryingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { + return onTransition(new RetryingSubscriptionState(error, onTransition)); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + throw new Error('Method not implemented.'); + }; + return OpeningSubscriptionState; + }()); + var RetryingSubscriptionState = (function () { + function RetryingSubscriptionState(error, onTransition) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); + var executeSubscriptionOnce = function (error) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = window.setTimeout(function () { + executeNextSubscribeStrategy(); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function () { + logger.verbose("RetryingSubscription: trying to re-establish the subscription"); + var underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { return executeSubscriptionOnce(error); }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error); + } + RetryingSubscriptionState.prototype.unsubscribe = function () { + window.clearTimeout(this.timeout); + this.onTransition(new EndedSubscriptionState()); + }; + return RetryingSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + this.onTransition(new EndedSubscriptionState()); + }; + return OpenSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return RetryingSubscription; + }()); + return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { + if (tokenProvider) { + return function (listeners, headers) { + return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); + }; + } + return nextSubscribeStrategy; +}; +var TokenProvidingSubscription = (function () { + function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { + var _this = this; + this.logger = logger; + this.listeners = listeners; + this.headers = headers; + this.tokenProvider = tokenProvider; + this.nextSubscribeStrategy = nextSubscribeStrategy; + this.unsubscribe = function () { + _this.state.unsubscribe(); + _this.state = new InactiveState(_this.logger); + }; + this.state = new ActiveState(logger, headers, nextSubscribeStrategy); + this.subscribe(); + } + TokenProvidingSubscription.prototype.subscribe = function () { + var _this = this; + this.tokenProvider + .fetchToken() + .then(function (token) { + var existingListeners = Object.assign({}, _this.listeners); + _this.state.subscribe(token, { + onEnd: function (error) { + _this.state = new InactiveState(_this.logger); + existingListeners.onEnd(error); + }, + onError: function (error) { + if (_this.isTokenExpiredError(error)) { + _this.tokenProvider.clearToken(token); + _this.subscribe(); + } + else { + _this.state = new InactiveState(_this.logger); + existingListeners.onError(error); + } + }, + onEvent: _this.listeners.onEvent, + onOpen: _this.listeners.onOpen, + }); + }) + .catch(function (error) { + _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); + _this.state = new InactiveState(_this.logger); + _this.listeners.onError(error); + }); + }; + TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { + return (error instanceof network_1.ErrorResponse && + error.statusCode === 401 && + error.info === 'authentication/expired'); + }; + return TokenProvidingSubscription; +}()); +var ActiveState = (function () { + function ActiveState(logger, headers, nextSubscribeStrategy) { + this.logger = logger; + this.headers = headers; + this.nextSubscribeStrategy = nextSubscribeStrategy; + logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); + } + ActiveState.prototype.subscribe = function (token, listeners) { + var _this = this; + this.putTokenIntoHeader(token); + this.underlyingSubscription = this.nextSubscribeStrategy({ + onEnd: function (error) { + _this.logger.verbose("TokenProvidingSubscription: subscription ended"); + listeners.onEnd(error); + }, + onError: function (error) { + _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); + listeners.onError(error); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + _this.logger.verbose("TokenProvidingSubscription: subscription opened"); + listeners.onOpen(headers); + }, + onRetrying: listeners.onRetrying, + }, this.headers); + }; + ActiveState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + }; + ActiveState.prototype.putTokenIntoHeader = function (token) { + this.headers['Authorization'] = "Bearer " + token; + this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); + }; + return ActiveState; +}()); +var InactiveState = (function () { + function InactiveState(logger) { + this.logger = logger; + logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); + } + InactiveState.prototype.subscribe = function (token, listeners) { + this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); + }; + InactiveState.prototype.unsubscribe = function () { + this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); + }; + return InactiveState; +}()); + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createTransportStrategy = function (path, transport, logger) { + return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; +}; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HOST_BASE = 'pusherplatform.io'; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +exports.BaseClient = base_client_1.BaseClient; +var host_base_1 = __webpack_require__(9); +exports.HOST_BASE = host_base_1.HOST_BASE; +var instance_1 = __webpack_require__(15); +exports.Instance = instance_1.default; +var logger_1 = __webpack_require__(1); +exports.ConsoleLogger = logger_1.ConsoleLogger; +exports.EmptyLogger = logger_1.EmptyLogger; +var network_1 = __webpack_require__(0); +exports.ErrorResponse = network_1.ErrorResponse; +exports.NetworkError = network_1.NetworkError; +exports.responseToHeadersObject = network_1.responseToHeadersObject; +exports.XhrReadyState = network_1.XhrReadyState; +var request_1 = __webpack_require__(4); +exports.executeNetworkRequest = request_1.executeNetworkRequest; +exports.sendRawRequest = request_1.sendRawRequest; +var resuming_subscription_1 = __webpack_require__(5); +exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; +exports.DoNotRetry = retry_strategy_1.DoNotRetry; +exports.Retry = retry_strategy_1.Retry; +exports.RetryResolution = retry_strategy_1.RetryResolution; +var retrying_subscription_1 = __webpack_require__(6); +exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; +var token_providing_subscription_1 = __webpack_require__(7); +exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; +var transports_1 = __webpack_require__(8); +exports.createTransportStrategy = transports_1.createTransportStrategy; +exports.default = { + BaseClient: base_client_1.BaseClient, + ConsoleLogger: logger_1.ConsoleLogger, + EmptyLogger: logger_1.EmptyLogger, + Instance: instance_1.default, +}; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { + return { + onEnd: subListeners.onEnd, + onError: subListeners.onError, + onEvent: subListeners.onEvent, + onOpen: subListeners.onOpen, + onRetrying: subListeners.onRetrying, + }; +}; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.replaceMissingListenersWithNoOps = function (listeners) { + var onEndNoOp = function (error) { }; + var onEnd = listeners.onEnd || onEndNoOp; + var onErrorNoOp = function (error) { }; + var onError = listeners.onError || onErrorNoOp; + var onEventNoOp = function (event) { }; + var onEvent = listeners.onEvent || onEventNoOp; + var onOpenNoOp = function (headers) { }; + var onOpen = listeners.onOpen || onOpenNoOp; + var onRetryingNoOp = function () { }; + var onRetrying = listeners.onRetrying || onRetryingNoOp; + var onSubscribeNoOp = function () { }; + var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; + return { + onEnd: onEnd, + onError: onError, + onEvent: onEvent, + onOpen: onOpen, + onRetrying: onRetrying, + onSubscribe: onSubscribe, + }; +}; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var HttpTransportState; +(function (HttpTransportState) { + HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; + HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; + HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; + HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; + HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; +})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); +var HttpSubscription = (function () { + function HttpSubscription(xhr, listeners) { + var _this = this; + this.gotEOS = false; + this.lastNewlineIndex = 0; + this.state = HttpTransportState.UNOPENED; + this.xhr = xhr; + this.listeners = listeners; + this.xhr.onreadystatechange = function () { + switch (_this.xhr.readyState) { + case network_1.XhrReadyState.UNSENT: + case network_1.XhrReadyState.OPENED: + case network_1.XhrReadyState.HEADERS_RECEIVED: + _this.assertStateIsIn(HttpTransportState.OPENING); + break; + case network_1.XhrReadyState.LOADING: + _this.onLoading(); + break; + case network_1.XhrReadyState.DONE: + _this.onDone(); + break; + } + }; + this.state = HttpTransportState.OPENING; + this.xhr.send(); + return this; + } + HttpSubscription.prototype.unsubscribe = function () { + this.state = HttpTransportState.ENDED; + this.xhr.abort(); + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + }; + HttpSubscription.prototype.onLoading = function () { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + window.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN); + var err = this.onChunk(); + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + if (err) { + this.state = HttpTransportState.ENDED; + if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else { + } + } + }; + HttpSubscription.prototype.onDone = function () { + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + var err = this.onChunk(); + if (err) { + this.state = HttpTransportState.ENDED; + if (err.statusCode === 204) { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else if (this.state <= HttpTransportState.ENDING) { + if (this.listeners.onError) { + this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); + } + } + else { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + } + else { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); + if (this.state === HttpTransportState.ENDED) { + return; + } + else if (this.xhr.status === 0) { + if (this.listeners.onError) { + this.listeners.onError(new network_1.NetworkError('Connection lost.')); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); + } + } + } + }; + HttpSubscription.prototype.onChunk = function () { + this.assertStateIsIn(HttpTransportState.OPEN); + var response = this.xhr.responseText; + var newlineIndex = response.lastIndexOf('\n'); + if (newlineIndex > this.lastNewlineIndex) { + var rawEvents = response + .slice(this.lastNewlineIndex, newlineIndex) + .split('\n'); + this.lastNewlineIndex = newlineIndex; + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + if (rawEvent.length === 0) { + continue; + } + var data = JSON.parse(rawEvent); + var err = this.onMessage(data); + if (err != null) { + return err; + } + } + } + }; + HttpSubscription.prototype.assertStateIsIn = function () { + var _this = this; + var validStates = []; + for (var _i = 0; _i < arguments.length; _i++) { + validStates[_i] = arguments[_i]; + } + var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); + if (!stateIsValid) { + var expectedStates = validStates + .map(function (state) { return HttpTransportState[state]; }) + .join(', '); + var actualState = HttpTransportState[this.state]; + window.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); + } + }; + HttpSubscription.prototype.onMessage = function (message) { + this.assertStateIsIn(HttpTransportState.OPEN); + this.verifyMessage(message); + switch (message[0]) { + case 0: + return null; + case 1: + return this.onEventMessage(message); + case 255: + return this.onEOSMessage(message); + default: + return new Error('Unknown Message: ' + JSON.stringify(message)); + } + }; + HttpSubscription.prototype.onEventMessage = function (eventMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eventMessage.length !== 4) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; + if (typeof id !== 'string') { + return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); + } + if (this.listeners.onEvent) { + this.listeners.onEvent({ body: body, headers: headers, eventId: id }); + } + return null; + }; + HttpSubscription.prototype.onEOSMessage = function (eosMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eosMessage.length !== 4) { + return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); + } + var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; + if (typeof statusCode !== 'number') { + return new Error('Invalid EOS Status Code'); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid EOS ElementsHeaders'); + } + this.state = HttpTransportState.ENDING; + return new network_1.ErrorResponse(statusCode, headers, info); + }; + HttpSubscription.prototype.verifyMessage = function (message) { + if (this.gotEOS) { + return new Error('Got another message after EOS message'); + } + if (!Array.isArray(message)) { + return new Error('Message is not an array'); + } + if (message.length < 1) { + return new Error('Message is empty array'); + } + }; + return HttpSubscription; +}()); +var HttpTransport = (function () { + function HttpTransport(host, encrypted) { + if (encrypted === void 0) { encrypted = true; } + this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; + } + HttpTransport.prototype.request = function (requestOptions) { + return this.createXHR(this.baseURL, requestOptions); + }; + HttpTransport.prototype.subscribe = function (path, listeners, headers) { + var requestOptions = { + headers: headers, + method: 'SUBSCRIBE', + path: path, + }; + return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); + }; + HttpTransport.prototype.createXHR = function (baseURL, options) { + var xhr = new window.XMLHttpRequest(); + var path = options.path.replace(/^\/+/, ''); + var endpoint = baseURL + "/" + path; + xhr.open(options.method.toUpperCase(), endpoint, true); + xhr = this.setJSONHeaderIfAppropriate(xhr, options); + if (options.jwt) { + xhr.setRequestHeader('authorization', "Bearer " + options.jwt); + } + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + return xhr; + }; + HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { + if (options.json) { + xhr.setRequestHeader('content-type', 'application/json'); + } + return xhr; + }; + return HttpTransport; +}()); +exports.default = HttpTransport; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var SubscribeMessageType = 100; +var OpenMessageType = 101; +var EventMessageType = 102; +var UnsubscribeMessageType = 198; +var EosMessageType = 199; +var PingMessageType = 16; +var PongMessageType = 17; +var CloseMessageType = 99; +var WSReadyState; +(function (WSReadyState) { + WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; + WSReadyState[WSReadyState["Open"] = 1] = "Open"; + WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; + WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; +})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); +var WsSubscriptions = (function () { + function WsSubscriptions() { + this.subscriptions = {}; + } + WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { + this.subscriptions[subID] = { + headers: headers, + listeners: listeners, + path: path, + }; + return subID; + }; + WsSubscriptions.prototype.has = function (subID) { + return this.subscriptions[subID] !== undefined; + }; + WsSubscriptions.prototype.isEmpty = function () { + return Object.keys(this.subscriptions).length === 0; + }; + WsSubscriptions.prototype.remove = function (subID) { + return delete this.subscriptions[subID]; + }; + WsSubscriptions.prototype.get = function (subID) { + return this.subscriptions[subID]; + }; + WsSubscriptions.prototype.getAll = function () { + return this.subscriptions; + }; + WsSubscriptions.prototype.getAllAsArray = function () { + var _this = this; + return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); + }; + WsSubscriptions.prototype.removeAll = function () { + this.subscriptions = {}; + }; + return WsSubscriptions; +}()); +var WsSubscription = (function () { + function WsSubscription(wsTransport, subID) { + this.wsTransport = wsTransport; + this.subID = subID; + } + WsSubscription.prototype.unsubscribe = function () { + this.wsTransport.unsubscribe(this.subID); + }; + return WsSubscription; +}()); +var pingIntervalMs = 30000; +var pingTimeoutMs = 10000; +var WebSocketTransport = (function () { + function WebSocketTransport(host) { + this.webSocketPath = '/ws'; + this.forcedClose = false; + this.closedError = null; + this.baseURL = "wss://" + host + this.webSocketPath; + this.lastSubscriptionID = 0; + this.subscriptions = new WsSubscriptions(); + this.pendingSubscriptions = new WsSubscriptions(); + this.connect(); + } + WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { + this.tryReconnectIfNeeded(); + var subID = this.lastSubscriptionID++; + if (this.socket.readyState !== WSReadyState.Open) { + this.pendingSubscriptions.add(subID, path, listeners, headers); + return new WsSubscription(this, subID); + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + return new WsSubscription(this, subID); + }; + WebSocketTransport.prototype.unsubscribe = function (subID) { + this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); + var subscription = this.subscriptions.get(subID); + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + this.subscriptions.remove(subID); + }; + WebSocketTransport.prototype.connect = function () { + var _this = this; + this.close(); + this.forcedClose = false; + this.closedError = null; + this.socket = new window.WebSocket(this.baseURL); + this.socket.onopen = function (event) { + var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); + allPendingSubscriptions.forEach(function (subscription) { + var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; + _this.subscribePending(path, listeners, headers, subID); + }); + _this.pendingSubscriptions.removeAll(); + _this.pingInterval = window.setInterval(function () { + if (_this.pongTimeout) { + return; + } + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + return; + } + _this.sendMessage(_this.getMessage(PingMessageType, now)); + _this.lastSentPingID = now; + _this.pongTimeout = window.setTimeout(function () { + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + _this.pongTimeout = null; + return; + } + _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); + }, pingTimeoutMs); + }, pingIntervalMs); + }; + this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; + this.socket.onerror = function (event) { + _this.close(new network_1.NetworkError('Connection was lost.')); + }; + this.socket.onclose = function (event) { + if (!_this.forcedClose) { + _this.tryReconnectIfNeeded(); + return; + } + var callback = _this.closedError + ? function (subscription) { + if (subscription.listeners.onError) { + subscription.listeners.onError(_this.closedError); + } + } + : function (subscription) { + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + }; + var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false + ? _this.pendingSubscriptions + : _this.subscriptions; + allSubscriptions.getAllAsArray().forEach(callback); + allSubscriptions.removeAll(); + if (_this.closedError) { + _this.tryReconnectIfNeeded(); + } + }; + }; + WebSocketTransport.prototype.close = function (error) { + if (!(this.socket instanceof window.WebSocket)) { + return; + } + this.forcedClose = true; + this.closedError = error; + this.socket.close(); + window.clearTimeout(this.pingInterval); + window.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.tryReconnectIfNeeded = function () { + if (this.socket.readyState !== WSReadyState.Closed) { + return; + } + this.connect(); + }; + WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { + if (subID === undefined) { + window.console.logger.debug("Subscription to path " + path + " has an undefined ID"); + return; + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + }; + WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { + return [messageType, id, path, headers]; + }; + WebSocketTransport.prototype.sendMessage = function (message) { + if (this.socket.readyState !== WSReadyState.Open) { + return window.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); + } + this.socket.send(JSON.stringify(message)); + }; + WebSocketTransport.prototype.subscription = function (subID) { + return this.subscriptions.get(subID); + }; + WebSocketTransport.prototype.receiveMessage = function (event) { + this.lastMessageReceivedTimestamp = new Date().getTime(); + var message; + try { + message = JSON.parse(event.data); + } + catch (err) { + this.close(new Error("Message is not valid JSON format. Getting " + event.data)); + return; + } + var nonValidMessageError = this.validateMessage(message); + if (nonValidMessageError) { + this.close(new Error(nonValidMessageError.message)); + return; + } + var messageType = message.shift(); + switch (messageType) { + case PongMessageType: + this.onPongMessage(message); + return; + case PingMessageType: + this.onPingMessage(message); + return; + case CloseMessageType: + this.onCloseMessage(message); + return; + } + var subID = message.shift(); + var subscription = this.subscription(subID); + if (!subscription) { + this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); + return; + } + var listeners = subscription.listeners; + switch (messageType) { + case OpenMessageType: + this.onOpenMessage(message, subID, listeners); + break; + case EventMessageType: + this.onEventMessage(message, listeners); + break; + case EosMessageType: + this.onEOSMessage(message, subID, listeners); + break; + default: + this.close(new Error('Received non existing type of message.')); + } + }; + WebSocketTransport.prototype.validateMessage = function (message) { + if (!Array.isArray(message)) { + return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); + } + if (message.length < 1) { + return new Error("Message is empty array: " + JSON.stringify(message)); + } + return null; + }; + WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { + if (subscriptionListeners.onOpen) { + subscriptionListeners.onOpen(message[1]); + } + }; + WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { + if (eventMessage.length !== 3) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; + if (typeof eventId !== 'string') { + return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); + } + if (subscriptionListeners.onEvent) { + subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); + } + }; + WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { + this.subscriptions.remove(subID); + if (eosMessage.length !== 3) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); + } + return; + } + var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; + if (typeof statusCode !== 'number') { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS Status Code')); + } + return; + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); + } + return; + } + if (statusCode === 204) { + if (subscriptionListeners.onEnd) { + subscriptionListeners.onEnd(null); + } + return; + } + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); + } + return; + }; + WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { + var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; + if (typeof statusCode !== 'number') { + return this.close(new Error('Close message: Invalid EOS Status Code')); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); + } + this.close(); + }; + WebSocketTransport.prototype.onPongMessage = function (message) { + var receviedPongID = message[0]; + if (this.lastSentPingID !== receviedPongID) { + this.close(new network_1.NetworkError("Didn't received pong with proper ID")); + } + window.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.onPingMessage = function (message) { + var receviedPingID = message[0]; + this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); + }; + return WebSocketTransport; +}()); +exports.default = WebSocketTransport; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +var host_base_1 = __webpack_require__(9); +var logger_1 = __webpack_require__(1); +var Instance = (function () { + function Instance(options) { + if (!options.locator) { + throw new Error('Expected `locator` property in Instance options!'); + } + var splitInstanceLocator = options.locator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instance locator property is in the wrong format!'); + } + if (!options.serviceName) { + throw new Error('Expected `serviceName` property in Instance options!'); + } + if (!options.serviceVersion) { + throw new Error('Expected `serviceVersion` property in Instance otpions!'); + } + this.platformVersion = splitInstanceLocator[0]; + this.cluster = splitInstanceLocator[1]; + this.id = splitInstanceLocator[2]; + this.serviceName = options.serviceName; + this.serviceVersion = options.serviceVersion; + this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.client = + options.client || + new base_client_1.BaseClient({ + encrypted: options.encrypted, + host: this.host, + logger: this.logger, + }); + this.tokenProvider = options.tokenProvider; + } + Instance.prototype.request = function (options, tokenParams) { + options.path = this.absPath(options.path); + if (options.headers == null || options.headers === undefined) { + options.headers = {}; + } + options.tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.request(options, tokenParams); + }; + Instance.prototype.subscribeNonResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); + }; + Instance.prototype.subscribeResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); + }; + Instance.prototype.absPath = function (relativePath) { + return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) + .replace(/\/+/g, '/') + .replace(/\/+$/, ''); + }; + return Instance; +}()); +exports.default = Instance; + + +/***/ }) +/******/ ]); +}); +}); + +unwrapExports(pusherPlatform); +var pusherPlatform_1 = pusherPlatform.BaseClient; +var pusherPlatform_2 = pusherPlatform.HOST_BASE; +var pusherPlatform_3 = pusherPlatform.Instance; +var pusherPlatform_4 = pusherPlatform.sendRawRequest; + +function _isPlaceholder(a) { + return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true; +} + +/** + * Optimized internal one-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry1(fn) { + return function f1(a) { + if (arguments.length === 0 || _isPlaceholder(a)) { + return f1; + } else { + return fn.apply(this, arguments); + } + }; +} + +/** + * Returns a function that always returns the given value. Note that for + * non-primitives the value returned is a reference to the original value. + * + * This function is known as `const`, `constant`, or `K` (for K combinator) in + * other languages and libraries. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig a -> (* -> a) + * @param {*} val The value to wrap in a function + * @return {Function} A Function :: * -> val. + * @example + * + * var t = R.always('Tee'); + * t(); //=> 'Tee' + */ +var always = /*#__PURE__*/_curry1(function always(val) { + return function () { + return val; + }; +}); + +/** + * A function that always returns `false`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig * -> Boolean + * @param {*} + * @return {Boolean} + * @see R.always, R.T + * @example + * + * R.F(); //=> false + */ +var F = /*#__PURE__*/always(false); + +/** + * A function that always returns `true`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig * -> Boolean + * @param {*} + * @return {Boolean} + * @see R.always, R.F + * @example + * + * R.T(); //=> true + */ +var T = /*#__PURE__*/always(true); + +/** + * A special placeholder value used to specify "gaps" within curried functions, + * allowing partial application of any combination of arguments, regardless of + * their positions. + * + * If `g` is a curried ternary function and `_` is `R.__`, the following are + * equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2, _)(1, 3)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @constant + * @memberOf R + * @since v0.6.0 + * @category Function + * @example + * + * var greet = R.replace('{name}', R.__, 'Hello, {name}!'); + * greet('Alice'); //=> 'Hello, Alice!' + */ + +/** + * Optimized internal two-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry2(fn) { + return function f2(a, b) { + switch (arguments.length) { + case 0: + return f2; + case 1: + return _isPlaceholder(a) ? f2 : _curry1(function (_b) { + return fn(a, _b); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) { + return fn(_a, b); + }) : _isPlaceholder(b) ? _curry1(function (_b) { + return fn(a, _b); + }) : fn(a, b); + } + }; +} + +/** + * Adds two values. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a + * @param {Number} b + * @return {Number} + * @see R.subtract + * @example + * + * R.add(2, 3); //=> 5 + * R.add(7)(10); //=> 17 + */ +var add = /*#__PURE__*/_curry2(function add(a, b) { + return Number(a) + Number(b); +}); + +/** + * Private `concat` function to merge two array-like objects. + * + * @private + * @param {Array|Arguments} [set1=[]] An array-like object. + * @param {Array|Arguments} [set2=[]] An array-like object. + * @return {Array} A new, merged array. + * @example + * + * _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + */ +function _concat(set1, set2) { + set1 = set1 || []; + set2 = set2 || []; + var idx; + var len1 = set1.length; + var len2 = set2.length; + var result = []; + + idx = 0; + while (idx < len1) { + result[result.length] = set1[idx]; + idx += 1; + } + idx = 0; + while (idx < len2) { + result[result.length] = set2[idx]; + idx += 1; + } + return result; +} + +function _arity(n, fn) { + /* eslint-disable no-unused-vars */ + switch (n) { + case 0: + return function () { + return fn.apply(this, arguments); + }; + case 1: + return function (a0) { + return fn.apply(this, arguments); + }; + case 2: + return function (a0, a1) { + return fn.apply(this, arguments); + }; + case 3: + return function (a0, a1, a2) { + return fn.apply(this, arguments); + }; + case 4: + return function (a0, a1, a2, a3) { + return fn.apply(this, arguments); + }; + case 5: + return function (a0, a1, a2, a3, a4) { + return fn.apply(this, arguments); + }; + case 6: + return function (a0, a1, a2, a3, a4, a5) { + return fn.apply(this, arguments); + }; + case 7: + return function (a0, a1, a2, a3, a4, a5, a6) { + return fn.apply(this, arguments); + }; + case 8: + return function (a0, a1, a2, a3, a4, a5, a6, a7) { + return fn.apply(this, arguments); + }; + case 9: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { + return fn.apply(this, arguments); + }; + case 10: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return fn.apply(this, arguments); + }; + default: + throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); + } +} + +/** + * Internal curryN function. + * + * @private + * @category Function + * @param {Number} length The arity of the curried function. + * @param {Array} received An array of arguments received thus far. + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curryN(length, received, fn) { + return function () { + var combined = []; + var argsIdx = 0; + var left = length; + var combinedIdx = 0; + while (combinedIdx < received.length || argsIdx < arguments.length) { + var result; + if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { + result = received[combinedIdx]; + } else { + result = arguments[argsIdx]; + argsIdx += 1; + } + combined[combinedIdx] = result; + if (!_isPlaceholder(result)) { + left -= 1; + } + combinedIdx += 1; + } + return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); + }; +} + +/** + * Returns a curried equivalent of the provided function, with the specified + * arity. The curried function has two unusual capabilities. First, its + * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the + * following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value [`R.__`](#__) may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @since v0.5.0 + * @category Function + * @sig Number -> (* -> a) -> (* -> a) + * @param {Number} length The arity for the returned function. + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curry + * @example + * + * var sumArgs = (...args) => R.sum(args); + * + * var curriedAddFourNumbers = R.curryN(4, sumArgs); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ +var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) { + if (length === 1) { + return _curry1(fn); + } + return _arity(length, _curryN(length, [], fn)); +}); + +/** + * Optimized internal three-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry3(fn) { + return function f3(a, b, c) { + switch (arguments.length) { + case 0: + return f3; + case 1: + return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) { + return fn(a, _b, _c); + }); + case 2: + return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) ? _curry2(function (_b, _c) { + return fn(a, _b, _c); + }) : _curry1(function (_c) { + return fn(a, b, _c); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) { + return fn(_a, _b, c); + }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) { + return fn(a, _b, _c); + }) : _isPlaceholder(a) ? _curry1(function (_a) { + return fn(_a, b, c); + }) : _isPlaceholder(b) ? _curry1(function (_b) { + return fn(a, _b, c); + }) : _isPlaceholder(c) ? _curry1(function (_c) { + return fn(a, b, _c); + }) : fn(a, b, c); + } + }; +} + +/** + * Tests whether or not an object is an array. + * + * @private + * @param {*} val The object to test. + * @return {Boolean} `true` if `val` is an array, `false` otherwise. + * @example + * + * _isArray([]); //=> true + * _isArray(null); //=> false + * _isArray({}); //=> false + */ +var _isArray = Array.isArray || function _isArray(val) { + return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]'; +}; + +function _isTransformer(obj) { + return typeof obj['@@transducer/step'] === 'function'; +} + +/** + * Returns a function that dispatches with different strategies based on the + * object in list position (last argument). If it is an array, executes [fn]. + * Otherwise, if it has a function with one of the given method names, it will + * execute that function (functor case). Otherwise, if it is a transformer, + * uses transducer [xf] to return a new transformer (transducer case). + * Otherwise, it will default to executing [fn]. + * + * @private + * @param {Array} methodNames properties to check for a custom implementation + * @param {Function} xf transducer to initialize if object is transformer + * @param {Function} fn default ramda implementation + * @return {Function} A function that dispatches on object in list position + */ +function _dispatchable(methodNames, xf, fn) { + return function () { + if (arguments.length === 0) { + return fn(); + } + var args = Array.prototype.slice.call(arguments, 0); + var obj = args.pop(); + if (!_isArray(obj)) { + var idx = 0; + while (idx < methodNames.length) { + if (typeof obj[methodNames[idx]] === 'function') { + return obj[methodNames[idx]].apply(obj, args); + } + idx += 1; + } + if (_isTransformer(obj)) { + var transducer = xf.apply(null, args); + return transducer(obj); + } + } + return fn.apply(this, arguments); + }; +} + +var _xfBase = { + init: function () { + return this.xf['@@transducer/init'](); + }, + result: function (result) { + return this.xf['@@transducer/result'](result); + } +}; + +/** + * Returns the larger of its two arguments. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig Ord a => a -> a -> a + * @param {*} a + * @param {*} b + * @return {*} + * @see R.maxBy, R.min + * @example + * + * R.max(789, 123); //=> 789 + * R.max('a', 'b'); //=> 'b' + */ +var max = /*#__PURE__*/_curry2(function max(a, b) { + return b > a ? b : a; +}); + +function _map(fn, functor) { + var idx = 0; + var len = functor.length; + var result = Array(len); + while (idx < len) { + result[idx] = fn(functor[idx]); + idx += 1; + } + return result; +} + +function _isString(x) { + return Object.prototype.toString.call(x) === '[object String]'; +} + +/** + * Tests whether or not an object is similar to an array. + * + * @private + * @category Type + * @category List + * @sig * -> Boolean + * @param {*} x The object to test. + * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise. + * @example + * + * _isArrayLike([]); //=> true + * _isArrayLike(true); //=> false + * _isArrayLike({}); //=> false + * _isArrayLike({length: 10}); //=> false + * _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true + */ +var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) { + if (_isArray(x)) { + return true; + } + if (!x) { + return false; + } + if (typeof x !== 'object') { + return false; + } + if (_isString(x)) { + return false; + } + if (x.nodeType === 1) { + return !!x.length; + } + if (x.length === 0) { + return true; + } + if (x.length > 0) { + return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); + } + return false; +}); + +var XWrap = /*#__PURE__*/function () { + function XWrap(fn) { + this.f = fn; + } + XWrap.prototype['@@transducer/init'] = function () { + throw new Error('init not implemented on XWrap'); + }; + XWrap.prototype['@@transducer/result'] = function (acc) { + return acc; + }; + XWrap.prototype['@@transducer/step'] = function (acc, x) { + return this.f(acc, x); + }; + + return XWrap; +}(); + +function _xwrap(fn) { + return new XWrap(fn); +} + +/** + * Creates a function that is bound to a context. + * Note: `R.bind` does not provide the additional argument-binding capabilities of + * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). + * + * @func + * @memberOf R + * @since v0.6.0 + * @category Function + * @category Object + * @sig (* -> *) -> {*} -> (* -> *) + * @param {Function} fn The function to bind to context + * @param {Object} thisObj The context to bind `fn` to + * @return {Function} A function that will execute in the context of `thisObj`. + * @see R.partial + * @example + * + * var log = R.bind(console.log, console); + * R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3} + * // logs {a: 2} + * @symb R.bind(f, o)(a, b) = f.call(o, a, b) + */ +var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) { + return _arity(fn.length, function () { + return fn.apply(thisObj, arguments); + }); +}); + +function _arrayReduce(xf, acc, list) { + var idx = 0; + var len = list.length; + while (idx < len) { + acc = xf['@@transducer/step'](acc, list[idx]); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + idx += 1; + } + return xf['@@transducer/result'](acc); +} + +function _iterableReduce(xf, acc, iter) { + var step = iter.next(); + while (!step.done) { + acc = xf['@@transducer/step'](acc, step.value); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + step = iter.next(); + } + return xf['@@transducer/result'](acc); +} + +function _methodReduce(xf, acc, obj, methodName) { + return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc)); +} + +var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator'; + +function _reduce(fn, acc, list) { + if (typeof fn === 'function') { + fn = _xwrap(fn); + } + if (_isArrayLike(list)) { + return _arrayReduce(fn, acc, list); + } + if (typeof list['fantasy-land/reduce'] === 'function') { + return _methodReduce(fn, acc, list, 'fantasy-land/reduce'); + } + if (list[symIterator] != null) { + return _iterableReduce(fn, acc, list[symIterator]()); + } + if (typeof list.next === 'function') { + return _iterableReduce(fn, acc, list); + } + if (typeof list.reduce === 'function') { + return _methodReduce(fn, acc, list, 'reduce'); + } + + throw new TypeError('reduce: list must be array or iterable'); +} + +var XMap = /*#__PURE__*/function () { + function XMap(f, xf) { + this.xf = xf; + this.f = f; + } + XMap.prototype['@@transducer/init'] = _xfBase.init; + XMap.prototype['@@transducer/result'] = _xfBase.result; + XMap.prototype['@@transducer/step'] = function (result, input) { + return this.xf['@@transducer/step'](result, this.f(input)); + }; + + return XMap; +}(); + +var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) { + return new XMap(f, xf); +}); + +function _has(prop, obj) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +var toString = Object.prototype.toString; +var _isArguments = function () { + return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) { + return toString.call(x) === '[object Arguments]'; + } : function _isArguments(x) { + return _has('callee', x); + }; +}; + +// cover IE < 9 keys issues +var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString'); +var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; +// Safari bug +var hasArgsEnumBug = /*#__PURE__*/function () { + return arguments.propertyIsEnumerable('length'); +}(); + +var contains = function contains(list, item) { + var idx = 0; + while (idx < list.length) { + if (list[idx] === item) { + return true; + } + idx += 1; + } + return false; +}; + +/** + * Returns a list containing the names of all the enumerable own properties of + * the supplied object. + * Note that the order of the output array is not guaranteed to be consistent + * across different JS platforms. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {k: v} -> [k] + * @param {Object} obj The object to extract properties from + * @return {Array} An array of the object's own properties. + * @see R.keysIn, R.values + * @example + * + * R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c'] + */ +var _keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? function keys(obj) { + return Object(obj) !== obj ? [] : Object.keys(obj); +} : function keys(obj) { + if (Object(obj) !== obj) { + return []; + } + var prop, nIdx; + var ks = []; + var checkArgsLength = hasArgsEnumBug && _isArguments(obj); + for (prop in obj) { + if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) { + ks[ks.length] = prop; + } + } + if (hasEnumBug) { + nIdx = nonEnumerableProps.length - 1; + while (nIdx >= 0) { + prop = nonEnumerableProps[nIdx]; + if (_has(prop, obj) && !contains(ks, prop)) { + ks[ks.length] = prop; + } + nIdx -= 1; + } + } + return ks; +}; +var keys = /*#__PURE__*/_curry1(_keys); + +/** + * Takes a function and + * a [functor](https://github.com/fantasyland/fantasy-land#functor), + * applies the function to each of the functor's values, and returns + * a functor of the same shape. + * + * Ramda provides suitable `map` implementations for `Array` and `Object`, + * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`. + * + * Dispatches to the `map` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * Also treats functions as functors and will compose them together. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Functor f => (a -> b) -> f a -> f b + * @param {Function} fn The function to be called on every element of the input `list`. + * @param {Array} list The list to be iterated over. + * @return {Array} The new list. + * @see R.transduce, R.addIndex + * @example + * + * var double = x => x * 2; + * + * R.map(double, [1, 2, 3]); //=> [2, 4, 6] + * + * R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6} + * @symb R.map(f, [a, b]) = [f(a), f(b)] + * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) } + * @symb R.map(f, functor_o) = functor_o.map(f) + */ +var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) { + switch (Object.prototype.toString.call(functor)) { + case '[object Function]': + return curryN(functor.length, function () { + return fn.call(this, functor.apply(this, arguments)); + }); + case '[object Object]': + return _reduce(function (acc, key) { + acc[key] = fn(functor[key]); + return acc; + }, {}, keys(functor)); + default: + return _map(fn, functor); + } +})); + +/** + * Retrieve the value at a given path. + * + * @func + * @memberOf R + * @since v0.2.0 + * @category Object + * @typedefn Idx = String | Int + * @sig [Idx] -> {a} -> a | Undefined + * @param {Array} path The path to use. + * @param {Object} obj The object to retrieve the nested property from. + * @return {*} The data at `path`. + * @see R.prop + * @example + * + * R.path(['a', 'b'], {a: {b: 2}}); //=> 2 + * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined + */ +var path = /*#__PURE__*/_curry2(function path(paths, obj) { + var val = obj; + var idx = 0; + while (idx < paths.length) { + if (val == null) { + return; + } + val = val[paths[idx]]; + idx += 1; + } + return val; +}); + +/** + * Returns a function that when supplied an object returns the indicated + * property of that object, if it exists. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig s -> {s: a} -> a | Undefined + * @param {String} p The property name + * @param {Object} obj The object to query + * @return {*} The value at `obj.p`. + * @see R.path + * @example + * + * R.prop('x', {x: 100}); //=> 100 + * R.prop('x', {}); //=> undefined + */ + +var prop = /*#__PURE__*/_curry2(function prop(p, obj) { + return path([p], obj); +}); + +/** + * Returns a new list by plucking the same named property off all objects in + * the list supplied. + * + * `pluck` will work on + * any [functor](https://github.com/fantasyland/fantasy-land#functor) in + * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Functor f => k -> f {k: v} -> f v + * @param {Number|String} key The key name to pluck off of each object. + * @param {Array} f The array or functor to consider. + * @return {Array} The list of values for the given key. + * @see R.props + * @example + * + * R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2] + * R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3] + * R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5} + * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5] + * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5] + */ +var pluck = /*#__PURE__*/_curry2(function pluck(p, list) { + return map(prop(p), list); +}); + +/** + * Returns a single item by iterating through the list, successively calling + * the iterator function and passing it an accumulator value and the current + * value from the array, and then passing the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It may use + * [`R.reduced`](#reduced) to shortcut the iteration. + * + * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function + * is *(value, acc)*. + * + * Note: `R.reduce` does not skip deleted or unassigned indices (sparse + * arrays), unlike the native `Array.prototype.reduce` method. For more details + * on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description + * + * Dispatches to the `reduce` method of the third argument, if present. When + * doing so, it is up to the user to handle the [`R.reduced`](#reduced) + * shortcuting, as this is not implemented by `reduce`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig ((a, b) -> a) -> a -> [b] -> a + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @see R.reduced, R.addIndex, R.reduceRight + * @example + * + * R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10 + * // - -10 + * // / \ / \ + * // - 4 -6 4 + * // / \ / \ + * // - 3 ==> -3 3 + * // / \ / \ + * // - 2 -1 2 + * // / \ / \ + * // 0 1 0 1 + * + * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d) + */ +var reduce = /*#__PURE__*/_curry3(_reduce); + +/** + * ap applies a list of functions to a list of values. + * + * Dispatches to the `ap` method of the second argument, if present. Also + * treats curried functions as applicatives. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category Function + * @sig [a -> b] -> [a] -> [b] + * @sig Apply f => f (a -> b) -> f a -> f b + * @sig (a -> b -> c) -> (a -> b) -> (a -> c) + * @param {*} applyF + * @param {*} applyX + * @return {*} + * @example + * + * R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6] + * R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"] + * + * // R.ap can also be used as S combinator + * // when only two functions are passed + * R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA' + * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)] + */ +var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) { + return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) { + return applyF(x)(applyX(x)); + } : + // else + _reduce(function (acc, f) { + return _concat(acc, map(f, applyX)); + }, [], applyF); +}); + +/** + * Returns a new list containing the contents of the given list, followed by + * the given element. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig a -> [a] -> [a] + * @param {*} el The element to add to the end of the new list. + * @param {Array} list The list of elements to add a new item to. + * list. + * @return {Array} A new list containing the elements of the old list followed by `el`. + * @see R.prepend + * @example + * + * R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests'] + * R.append('tests', []); //=> ['tests'] + * R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']] + */ +var append = /*#__PURE__*/_curry2(function append(el, list) { + return _concat(list, [el]); +}); + +/** + * Returns a list of all the enumerable own properties of the supplied object. + * Note that the order of the output array is not guaranteed across different + * JS platforms. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {k: v} -> [v] + * @param {Object} obj The object to extract values from + * @return {Array} An array of the values of the object's own properties. + * @see R.valuesIn, R.keys + * @example + * + * R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3] + */ +var values = /*#__PURE__*/_curry1(function values(obj) { + var props = keys(obj); + var len = props.length; + var vals = []; + var idx = 0; + while (idx < len) { + vals[idx] = obj[props[idx]]; + idx += 1; + } + return vals; +}); + +/** + * Determine if the passed argument is an integer. + * + * @private + * @param {*} n + * @category Type + * @return {Boolean} + */ + +function _isFunction(x) { + return Object.prototype.toString.call(x) === '[object Function]'; +} + +/** + * "lifts" a function to be the specified arity, so that it may "map over" that + * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). + * + * @func + * @memberOf R + * @since v0.7.0 + * @category Function + * @sig Number -> (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The lifted function. + * @see R.lift, R.ap + * @example + * + * var madd3 = R.liftN(3, (...args) => R.sum(args)); + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + */ +var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) { + var lifted = curryN(arity, fn); + return curryN(arity, function () { + return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1)); + }); +}); + +/** + * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other + * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). + * + * @func + * @memberOf R + * @since v0.7.0 + * @category Function + * @sig (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The lifted function. + * @see R.liftN + * @example + * + * var madd3 = R.lift((a, b, c) => a + b + c); + * + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + * + * var madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e); + * + * madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24] + */ +var lift = /*#__PURE__*/_curry1(function lift(fn) { + return liftN(fn.length, fn); +}); + +/** + * Returns a curried equivalent of the provided function. The curried function + * has two unusual capabilities. First, its arguments needn't be provided one + * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the + * following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value [`R.__`](#__) may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (* -> a) -> (* -> a) + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curryN + * @example + * + * var addFourNumbers = (a, b, c, d) => a + b + c + d; + * + * var curriedAddFourNumbers = R.curry(addFourNumbers); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ +var curry = /*#__PURE__*/_curry1(function curry(fn) { + return curryN(fn.length, fn); +}); + +/** + * Returns the result of calling its first argument with the remaining + * arguments. This is occasionally useful as a converging function for + * [`R.converge`](#converge): the first branch can produce a function while the + * remaining branches produce values to be passed to that function as its + * arguments. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig (*... -> a),*... -> a + * @param {Function} fn The function to apply to the remaining arguments. + * @param {...*} args Any number of positional arguments. + * @return {*} + * @see R.apply + * @example + * + * R.call(R.add, 1, 2); //=> 3 + * + * var indentN = R.pipe(R.repeat(' '), + * R.join(''), + * R.replace(/^(?!$)/gm)); + * + * var format = R.converge(R.call, [ + * R.pipe(R.prop('indent'), indentN), + * R.prop('value') + * ]); + * + * format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> ' foo\n bar\n baz\n' + * @symb R.call(f, a, b) = f(a, b) + */ +var call = /*#__PURE__*/curry(function call(fn) { + return fn.apply(this, Array.prototype.slice.call(arguments, 1)); +}); + +/** + * `_makeFlat` is a helper function that returns a one-level or fully recursive + * function based on the flag passed in. + * + * @private + */ +function _makeFlat(recursive) { + return function flatt(list) { + var value, jlen, j; + var result = []; + var idx = 0; + var ilen = list.length; + + while (idx < ilen) { + if (_isArrayLike(list[idx])) { + value = recursive ? flatt(list[idx]) : list[idx]; + j = 0; + jlen = value.length; + while (j < jlen) { + result[result.length] = value[j]; + j += 1; + } + } else { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; + }; +} + +function _forceReduced(x) { + return { + '@@transducer/value': x, + '@@transducer/reduced': true + }; +} + +var preservingReduced = function (xf) { + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return xf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + var ret = xf['@@transducer/step'](result, input); + return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret; + } + }; +}; + +var _flatCat = function _xcat(xf) { + var rxf = preservingReduced(xf); + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return rxf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input); + } + }; +}; + +var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) { + return map(f, _flatCat(xf)); +}); + +/** + * `chain` maps a function over a list and concatenates the results. `chain` + * is also known as `flatMap` in some libraries + * + * Dispatches to the `chain` method of the second argument, if present, + * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain). + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig Chain m => (a -> m b) -> m a -> m b + * @param {Function} fn The function to map with + * @param {Array} list The list to map over + * @return {Array} The result of flat-mapping `list` with `fn` + * @example + * + * var duplicate = n => [n, n]; + * R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3] + * + * R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1] + */ +var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { + if (typeof monad === 'function') { + return function (x) { + return fn(monad(x))(x); + }; + } + return _makeFlat(false)(map(fn, monad)); +})); + +function _cloneRegExp(pattern) { + return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : '')); +} + +/** + * Gives a single-word string description of the (native) type of a value, + * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not + * attempt to distinguish user Object types any further, reporting them all as + * 'Object'. + * + * @func + * @memberOf R + * @since v0.8.0 + * @category Type + * @sig (* -> {*}) -> String + * @param {*} val The value to test + * @return {String} + * @example + * + * R.type({}); //=> "Object" + * R.type(1); //=> "Number" + * R.type(false); //=> "Boolean" + * R.type('s'); //=> "String" + * R.type(null); //=> "Null" + * R.type([]); //=> "Array" + * R.type(/[A-z]/); //=> "RegExp" + * R.type(() => {}); //=> "Function" + * R.type(undefined); //=> "Undefined" + */ +var type = /*#__PURE__*/_curry1(function type(val) { + return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1); +}); + +/** + * Copies an object. + * + * @private + * @param {*} value The value to be copied + * @param {Array} refFrom Array containing the source references + * @param {Array} refTo Array containing the copied source references + * @param {Boolean} deep Whether or not to perform deep cloning. + * @return {*} The copied value. + */ +function _clone(value, refFrom, refTo, deep) { + var copy = function copy(copiedValue) { + var len = refFrom.length; + var idx = 0; + while (idx < len) { + if (value === refFrom[idx]) { + return refTo[idx]; + } + idx += 1; + } + refFrom[idx + 1] = value; + refTo[idx + 1] = copiedValue; + for (var key in value) { + copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key]; + } + return copiedValue; + }; + switch (type(value)) { + case 'Object': + return copy({}); + case 'Array': + return copy([]); + case 'Date': + return new Date(value.valueOf()); + case 'RegExp': + return _cloneRegExp(value); + default: + return value; + } +} + +/** + * Creates a deep copy of the value which may contain (nested) `Array`s and + * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are + * assigned by reference rather than copied + * + * Dispatches to a `clone` method if present. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {*} -> {*} + * @param {*} value The object or array to clone + * @return {*} A deeply cloned copy of `val` + * @example + * + * var objects = [{}, {}, {}]; + * var objectsClone = R.clone(objects); + * objects === objectsClone; //=> false + * objects[0] === objectsClone[0]; //=> false + */ +var clone = /*#__PURE__*/_curry1(function clone(value) { + return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true); +}); + +/** + * A function that returns the `!` of its argument. It will return `true` when + * passed false-y value, and `false` when passed a truth-y one. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Logic + * @sig * -> Boolean + * @param {*} a any value + * @return {Boolean} the logical inverse of passed argument. + * @see R.complement + * @example + * + * R.not(true); //=> false + * R.not(false); //=> true + * R.not(0); //=> true + * R.not(1); //=> false + */ +var not = /*#__PURE__*/_curry1(function not(a) { + return !a; +}); + +/** + * Takes a function `f` and returns a function `g` such that if called with the same arguments + * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`. + * + * `R.complement` may be applied to any functor + * + * @func + * @memberOf R + * @since v0.12.0 + * @category Logic + * @sig (*... -> *) -> (*... -> Boolean) + * @param {Function} f + * @return {Function} + * @see R.not + * @example + * + * var isNotNil = R.complement(R.isNil); + * isNil(null); //=> true + * isNotNil(null); //=> false + * isNil(7); //=> false + * isNotNil(7); //=> true + */ +var complement = /*#__PURE__*/lift(not); + +function _pipe(f, g) { + return function () { + return g.call(this, f.apply(this, arguments)); + }; +} + +/** + * This checks whether a function has a [methodname] function. If it isn't an + * array it will execute that function otherwise it will default to the ramda + * implementation. + * + * @private + * @param {Function} fn ramda implemtation + * @param {String} methodname property to check for a custom implementation + * @return {Object} Whatever the return value of the method is. + */ +function _checkForMethod(methodname, fn) { + return function () { + var length = arguments.length; + if (length === 0) { + return fn(); + } + var obj = arguments[length - 1]; + return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1)); + }; +} + +/** + * Returns the elements of the given list or string (or object with a `slice` + * method) from `fromIndex` (inclusive) to `toIndex` (exclusive). + * + * Dispatches to the `slice` method of the third argument, if present. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig Number -> Number -> [a] -> [a] + * @sig Number -> Number -> String -> String + * @param {Number} fromIndex The start index (inclusive). + * @param {Number} toIndex The end index (exclusive). + * @param {*} list + * @return {*} + * @example + * + * R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd'] + * R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c'] + * R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(0, 3, 'ramda'); //=> 'ram' + */ +var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) { + return Array.prototype.slice.call(list, fromIndex, toIndex); +})); + +/** + * Returns all but the first element of the given list or string (or object + * with a `tail` method). + * + * Dispatches to the `slice` method of the first argument, if present. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.head, R.init, R.last + * @example + * + * R.tail([1, 2, 3]); //=> [2, 3] + * R.tail([1, 2]); //=> [2] + * R.tail([1]); //=> [] + * R.tail([]); //=> [] + * + * R.tail('abc'); //=> 'bc' + * R.tail('ab'); //=> 'b' + * R.tail('a'); //=> '' + * R.tail(''); //=> '' + */ +var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity))); + +/** + * Performs left-to-right function composition. The leftmost function may have + * any arity; the remaining functions must be unary. + * + * In some libraries this function is named `sequence`. + * + * **Note:** The result of pipe is not automatically curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z) + * @param {...Function} functions + * @return {Function} + * @see R.compose + * @example + * + * var f = R.pipe(Math.pow, R.negate, R.inc); + * + * f(3, 4); // -(3^4) + 1 + * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b))) + */ +function pipe() { + if (arguments.length === 0) { + throw new Error('pipe requires at least one argument'); + } + return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments))); +} + +/** + * Returns a new list or string with the elements or characters in reverse + * order. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {Array|String} list + * @return {Array|String} + * @example + * + * R.reverse([1, 2, 3]); //=> [3, 2, 1] + * R.reverse([1, 2]); //=> [2, 1] + * R.reverse([1]); //=> [1] + * R.reverse([]); //=> [] + * + * R.reverse('abc'); //=> 'cba' + * R.reverse('ab'); //=> 'ba' + * R.reverse('a'); //=> 'a' + * R.reverse(''); //=> '' + */ +var reverse = /*#__PURE__*/_curry1(function reverse(list) { + return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse(); +}); + +/** + * Performs right-to-left function composition. The rightmost function may have + * any arity; the remaining functions must be unary. + * + * **Note:** The result of compose is not automatically curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z) + * @param {...Function} ...functions The functions to compose + * @return {Function} + * @see R.pipe + * @example + * + * var classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName + * var yellGreeting = R.compose(R.toUpper, classyGreeting); + * yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND" + * + * R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7 + * + * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b))) + */ +function compose() { + if (arguments.length === 0) { + throw new Error('compose requires at least one argument'); + } + return pipe.apply(this, reverse(arguments)); +} + +function _arrayFromIterator(iter) { + var list = []; + var next; + while (!(next = iter.next()).done) { + list.push(next.value); + } + return list; +} + +function _containsWith(pred, x, list) { + var idx = 0; + var len = list.length; + + while (idx < len) { + if (pred(x, list[idx])) { + return true; + } + idx += 1; + } + return false; +} + +function _functionName(f) { + // String(x => x) evaluates to "x => x", so the pattern may not match. + var match = String(f).match(/^function (\w*)/); + return match == null ? '' : match[1]; +} + +/** + * Returns true if its arguments are identical, false otherwise. Values are + * identical if they reference the same memory. `NaN` is identical to `NaN`; + * `0` and `-0` are not identical. + * + * @func + * @memberOf R + * @since v0.15.0 + * @category Relation + * @sig a -> a -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * var o = {}; + * R.identical(o, o); //=> true + * R.identical(1, 1); //=> true + * R.identical(1, '1'); //=> false + * R.identical([], []); //=> false + * R.identical(0, -0); //=> false + * R.identical(NaN, NaN); //=> true + */ +var identical = /*#__PURE__*/_curry2(function identical(a, b) { + // SameValue algorithm + if (a === b) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + return a !== 0 || 1 / a === 1 / b; + } else { + // Step 6.a: NaN == NaN + return a !== a && b !== b; + } +}); + +/** + * private _uniqContentEquals function. + * That function is checking equality of 2 iterator contents with 2 assumptions + * - iterators lengths are the same + * - iterators values are unique + * + * false-positive result will be returned for comparision of, e.g. + * - [1,2,3] and [1,2,3,4] + * - [1,1,1] and [1,2,3] + * */ + +function _uniqContentEquals(aIterator, bIterator, stackA, stackB) { + var a = _arrayFromIterator(aIterator); + var b = _arrayFromIterator(bIterator); + + function eq(_a, _b) { + return _equals(_a, _b, stackA.slice(), stackB.slice()); + } + + // if *a* array contains any element that is not included in *b* + return !_containsWith(function (b, aItem) { + return !_containsWith(eq, aItem, b); + }, b, a); +} + +function _equals(a, b, stackA, stackB) { + if (identical(a, b)) { + return true; + } + + var typeA = type(a); + + if (typeA !== type(b)) { + return false; + } + + if (a == null || b == null) { + return false; + } + + if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') { + return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a); + } + + if (typeof a.equals === 'function' || typeof b.equals === 'function') { + return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a); + } + + switch (typeA) { + case 'Arguments': + case 'Array': + case 'Object': + if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') { + return a === b; + } + break; + case 'Boolean': + case 'Number': + case 'String': + if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf()))) { + return false; + } + break; + case 'Date': + if (!identical(a.valueOf(), b.valueOf())) { + return false; + } + break; + case 'Error': + return a.name === b.name && a.message === b.message; + case 'RegExp': + if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) { + return false; + } + break; + } + + var idx = stackA.length - 1; + while (idx >= 0) { + if (stackA[idx] === a) { + return stackB[idx] === b; + } + idx -= 1; + } + + switch (typeA) { + case 'Map': + if (a.size !== b.size) { + return false; + } + + return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b])); + case 'Set': + if (a.size !== b.size) { + return false; + } + + return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b])); + case 'Arguments': + case 'Array': + case 'Object': + case 'Boolean': + case 'Number': + case 'String': + case 'Date': + case 'Error': + case 'RegExp': + case 'Int8Array': + case 'Uint8Array': + case 'Uint8ClampedArray': + case 'Int16Array': + case 'Uint16Array': + case 'Int32Array': + case 'Uint32Array': + case 'Float32Array': + case 'Float64Array': + case 'ArrayBuffer': + break; + default: + // Values of other types are only equal if identical. + return false; + } + + var keysA = keys(a); + if (keysA.length !== keys(b).length) { + return false; + } + + var extendedStackA = stackA.concat([a]); + var extendedStackB = stackB.concat([b]); + + idx = keysA.length - 1; + while (idx >= 0) { + var key = keysA[idx]; + if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) { + return false; + } + idx -= 1; + } + return true; +} + +/** + * Returns `true` if its arguments are equivalent, `false` otherwise. Handles + * cyclical data structures. + * + * Dispatches symmetrically to the `equals` methods of both arguments, if + * present. + * + * @func + * @memberOf R + * @since v0.15.0 + * @category Relation + * @sig a -> b -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * R.equals(1, 1); //=> true + * R.equals(1, '1'); //=> false + * R.equals([1, 2, 3], [1, 2, 3]); //=> true + * + * var a = {}; a.v = a; + * var b = {}; b.v = b; + * R.equals(a, b); //=> true + */ +var equals = /*#__PURE__*/_curry2(function equals(a, b) { + return _equals(a, b, [], []); +}); + +function _indexOf(list, a, idx) { + var inf, item; + // Array.prototype.indexOf doesn't exist below IE9 + if (typeof list.indexOf === 'function') { + switch (typeof a) { + case 'number': + if (a === 0) { + // manually crawl the list to distinguish between +0 and -0 + inf = 1 / a; + while (idx < list.length) { + item = list[idx]; + if (item === 0 && 1 / item === inf) { + return idx; + } + idx += 1; + } + return -1; + } else if (a !== a) { + // NaN + while (idx < list.length) { + item = list[idx]; + if (typeof item === 'number' && item !== item) { + return idx; + } + idx += 1; + } + return -1; + } + // non-zero numbers can utilise Set + return list.indexOf(a, idx); + + // all these types can utilise Set + case 'string': + case 'boolean': + case 'function': + case 'undefined': + return list.indexOf(a, idx); + + case 'object': + if (a === null) { + // null can utilise Set + return list.indexOf(a, idx); + } + } + } + // anything else not covered above, defer to R.equals + while (idx < list.length) { + if (equals(list[idx], a)) { + return idx; + } + idx += 1; + } + return -1; +} + +function _contains(a, list) { + return _indexOf(list, a, 0) >= 0; +} + +function _quote(s) { + var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace + .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0'); + + return '"' + escaped.replace(/"/g, '\\"') + '"'; +} + +/** + * Polyfill from . + */ +var pad = function pad(n) { + return (n < 10 ? '0' : '') + n; +}; + +var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) { + return d.toISOString(); +} : function _toISOString(d) { + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'; +}; + +function _complement(f) { + return function () { + return !f.apply(this, arguments); + }; +} + +function _filter(fn, list) { + var idx = 0; + var len = list.length; + var result = []; + + while (idx < len) { + if (fn(list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; +} + +function _isObject(x) { + return Object.prototype.toString.call(x) === '[object Object]'; +} + +var XFilter = /*#__PURE__*/function () { + function XFilter(f, xf) { + this.xf = xf; + this.f = f; + } + XFilter.prototype['@@transducer/init'] = _xfBase.init; + XFilter.prototype['@@transducer/result'] = _xfBase.result; + XFilter.prototype['@@transducer/step'] = function (result, input) { + return this.f(input) ? this.xf['@@transducer/step'](result, input) : result; + }; + + return XFilter; +}(); + +var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) { + return new XFilter(f, xf); +}); + +/** + * Takes a predicate and a `Filterable`, and returns a new filterable of the + * same type containing the members of the given filterable which satisfy the + * given predicate. Filterable objects include plain objects or any object + * that has a filter method such as `Array`. + * + * Dispatches to the `filter` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> f a + * @param {Function} pred + * @param {Array} filterable + * @return {Array} Filterable + * @see R.reject, R.transduce, R.addIndex + * @example + * + * var isEven = n => n % 2 === 0; + * + * R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4] + * + * R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} + */ +var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) { + return _isObject(filterable) ? _reduce(function (acc, key) { + if (pred(filterable[key])) { + acc[key] = filterable[key]; + } + return acc; + }, {}, keys(filterable)) : + // else + _filter(pred, filterable); +})); + +/** + * The complement of [`filter`](#filter). + * + * Acts as a transducer if a transformer is given in list position. Filterable + * objects include plain objects or any object that has a filter method such + * as `Array`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> f a + * @param {Function} pred + * @param {Array} filterable + * @return {Array} + * @see R.filter, R.transduce, R.addIndex + * @example + * + * var isOdd = (n) => n % 2 === 1; + * + * R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4] + * + * R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} + */ +var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) { + return filter(_complement(pred), filterable); +}); + +function _toString(x, seen) { + var recur = function recur(y) { + var xs = seen.concat([x]); + return _contains(y, xs) ? '' : _toString(y, xs); + }; + + // mapPairs :: (Object, [String]) -> [String] + var mapPairs = function (obj, keys$$1) { + return _map(function (k) { + return _quote(k) + ': ' + recur(obj[k]); + }, keys$$1.slice().sort()); + }; + + switch (Object.prototype.toString.call(x)) { + case '[object Arguments]': + return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))'; + case '[object Array]': + return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) { + return (/^\d+$/.test(k) + ); + }, keys(x)))).join(', ') + ']'; + case '[object Boolean]': + return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString(); + case '[object Date]': + return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')'; + case '[object Null]': + return 'null'; + case '[object Number]': + return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10); + case '[object String]': + return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x); + case '[object Undefined]': + return 'undefined'; + default: + if (typeof x.toString === 'function') { + var repr = x.toString(); + if (repr !== '[object Object]') { + return repr; + } + } + return '{' + mapPairs(x, keys(x)).join(', ') + '}'; + } +} + +/** + * Returns the string representation of the given value. `eval`'ing the output + * should result in a value equivalent to the input value. Many of the built-in + * `toString` methods do not satisfy this requirement. + * + * If the given value is an `[object Object]` with a `toString` method other + * than `Object.prototype.toString`, this method is invoked with no arguments + * to produce the return value. This means user-defined constructor functions + * can provide a suitable `toString` method. For example: + * + * function Point(x, y) { + * this.x = x; + * this.y = y; + * } + * + * Point.prototype.toString = function() { + * return 'new Point(' + this.x + ', ' + this.y + ')'; + * }; + * + * R.toString(new Point(1, 2)); //=> 'new Point(1, 2)' + * + * @func + * @memberOf R + * @since v0.14.0 + * @category String + * @sig * -> String + * @param {*} val + * @return {String} + * @example + * + * R.toString(42); //=> '42' + * R.toString('abc'); //=> '"abc"' + * R.toString([1, 2, 3]); //=> '[1, 2, 3]' + * R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}' + * R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")' + */ +var toString$1 = /*#__PURE__*/_curry1(function toString(val) { + return _toString(val, []); +}); + +/** + * Returns the result of concatenating the given lists or strings. + * + * Note: `R.concat` expects both arguments to be of the same type, + * unlike the native `Array.prototype.concat` method. It will throw + * an error if you `concat` an Array with a non-Array value. + * + * Dispatches to the `concat` method of the first argument, if present. + * Can also concatenate two members of a [fantasy-land + * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup). + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] -> [a] + * @sig String -> String -> String + * @param {Array|String} firstList The first list + * @param {Array|String} secondList The second list + * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of + * `secondList`. + * + * @example + * + * R.concat('ABC', 'DEF'); // 'ABCDEF' + * R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + * R.concat([], []); //=> [] + */ +var concat = /*#__PURE__*/_curry2(function concat(a, b) { + if (_isArray(a)) { + if (_isArray(b)) { + return a.concat(b); + } + throw new TypeError(toString$1(b) + ' is not an array'); + } + if (_isString(a)) { + if (_isString(b)) { + return a + b; + } + throw new TypeError(toString$1(b) + ' is not a string'); + } + if (a != null && _isFunction(a['fantasy-land/concat'])) { + return a['fantasy-land/concat'](b); + } + if (a != null && _isFunction(a.concat)) { + return a.concat(b); + } + throw new TypeError(toString$1(a) + ' does not have a method named "concat" or "fantasy-land/concat"'); +}); + +/** + * Returns `true` if the specified value is equal, in [`R.equals`](#equals) + * terms, to at least one element of the given list; `false` otherwise. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig a -> [a] -> Boolean + * @param {Object} a The item to compare against. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise. + * @see R.any + * @example + * + * R.contains(3, [1, 2, 3]); //=> true + * R.contains(4, [1, 2, 3]); //=> false + * R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true + * R.contains([42], [[42]]); //=> true + */ +var contains$1 = /*#__PURE__*/_curry2(_contains); + +/** + * Accepts a converging function and a list of branching functions and returns + * a new function. When invoked, this new function is applied to some + * arguments, each branching function is applied to those same arguments. The + * results of each branching function are passed as arguments to the converging + * function to produce the return value. + * + * @func + * @memberOf R + * @since v0.4.2 + * @category Function + * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z) + * @param {Function} after A function. `after` will be invoked with the return values of + * `fn1` and `fn2` as its arguments. + * @param {Array} functions A list of functions. + * @return {Function} A new function. + * @see R.useWith + * @example + * + * var average = R.converge(R.divide, [R.sum, R.length]) + * average([1, 2, 3, 4, 5, 6, 7]) //=> 4 + * + * var strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower]) + * strangeConcat("Yodel") //=> "YODELyodel" + * + * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b)) + */ +var converge = /*#__PURE__*/_curry2(function converge(after, fns) { + return curryN(reduce(max, 0, pluck('length', fns)), function () { + var args = arguments; + var context = this; + return after.apply(context, _map(function (fn) { + return fn.apply(context, args); + }, fns)); + }); +}); + +var XReduceBy = /*#__PURE__*/function () { + function XReduceBy(valueFn, valueAcc, keyFn, xf) { + this.valueFn = valueFn; + this.valueAcc = valueAcc; + this.keyFn = keyFn; + this.xf = xf; + this.inputs = {}; + } + XReduceBy.prototype['@@transducer/init'] = _xfBase.init; + XReduceBy.prototype['@@transducer/result'] = function (result) { + var key; + for (key in this.inputs) { + if (_has(key, this.inputs)) { + result = this.xf['@@transducer/step'](result, this.inputs[key]); + if (result['@@transducer/reduced']) { + result = result['@@transducer/value']; + break; + } + } + } + this.inputs = null; + return this.xf['@@transducer/result'](result); + }; + XReduceBy.prototype['@@transducer/step'] = function (result, input) { + var key = this.keyFn(input); + this.inputs[key] = this.inputs[key] || [key, this.valueAcc]; + this.inputs[key][1] = this.valueFn(this.inputs[key][1], input); + return result; + }; + + return XReduceBy; +}(); + +var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) { + return new XReduceBy(valueFn, valueAcc, keyFn, xf); +}); + +/** + * Groups the elements of the list according to the result of calling + * the String-returning function `keyFn` on each element and reduces the elements + * of each group to a single value via the reducer function `valueFn`. + * + * This function is basically a more general [`groupBy`](#groupBy) function. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.20.0 + * @category List + * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a} + * @param {Function} valueFn The function that reduces the elements of each group to a single + * value. Receives two values, accumulator for a particular group and the current element. + * @param {*} acc The (initial) accumulator value for each group. + * @param {Function} keyFn The function that maps the list's element into a key. + * @param {Array} list The array to group. + * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of + * `valueFn` for elements which produced that key when passed to `keyFn`. + * @see R.groupBy, R.reduce + * @example + * + * var reduceToNamesBy = R.reduceBy((acc, student) => acc.concat(student.name), []); + * var namesByGrade = reduceToNamesBy(function(student) { + * var score = student.score; + * return score < 65 ? 'F' : + * score < 70 ? 'D' : + * score < 80 ? 'C' : + * score < 90 ? 'B' : 'A'; + * }); + * var students = [{name: 'Lucy', score: 92}, + * {name: 'Drew', score: 85}, + * // ... + * {name: 'Bart', score: 62}]; + * namesByGrade(students); + * // { + * // 'A': ['Lucy'], + * // 'B': ['Drew'] + * // // ..., + * // 'F': ['Bart'] + * // } + */ +var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) { + return _reduce(function (acc, elt) { + var key = keyFn(elt); + acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt); + return acc; + }, {}, list); +})); + +/** + * Counts the elements of a list according to how many match each value of a + * key generated by the supplied function. Returns an object mapping the keys + * produced by `fn` to the number of occurrences in the list. Note that all + * keys are coerced to strings because of how JavaScript objects work. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig (a -> String) -> [a] -> {*} + * @param {Function} fn The function used to map values to keys. + * @param {Array} list The list to count elements from. + * @return {Object} An object mapping keys to number of occurrences in the list. + * @example + * + * var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2]; + * R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1} + * + * var letters = ['a', 'b', 'A', 'a', 'B', 'c']; + * R.countBy(R.toLower)(letters); //=> {'a': 3, 'b': 2, 'c': 1} + */ +var countBy = /*#__PURE__*/reduceBy(function (acc, elem) { + return acc + 1; +}, 0); + +/** + * Decrements its argument. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} n - 1 + * @see R.inc + * @example + * + * R.dec(42); //=> 41 + */ +var dec = /*#__PURE__*/add(-1); + +/** + * Finds the set (i.e. no duplicates) of all elements in the first list not + * contained in the second list. Objects and Arrays are compared in terms of + * value equality, not reference equality. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig [*] -> [*] -> [*] + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @return {Array} The elements in `list1` that are not in `list2`. + * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without + * @example + * + * R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2] + * R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5] + * R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}] + */ +var difference = /*#__PURE__*/_curry2(function difference(first, second) { + var out = []; + var idx = 0; + var firstLen = first.length; + while (idx < firstLen) { + if (!_contains(first[idx], second) && !_contains(first[idx], out)) { + out[out.length] = first[idx]; + } + idx += 1; + } + return out; +}); + +var XDropRepeatsWith = /*#__PURE__*/function () { + function XDropRepeatsWith(pred, xf) { + this.xf = xf; + this.pred = pred; + this.lastValue = undefined; + this.seenFirstValue = false; + } + + XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init; + XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result; + XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) { + var sameAsLast = false; + if (!this.seenFirstValue) { + this.seenFirstValue = true; + } else if (this.pred(this.lastValue, input)) { + sameAsLast = true; + } + this.lastValue = input; + return sameAsLast ? result : this.xf['@@transducer/step'](result, input); + }; + + return XDropRepeatsWith; +}(); + +var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) { + return new XDropRepeatsWith(pred, xf); +}); + +/** + * Returns the nth element of the given list or string. If n is negative the + * element at index length + n is returned. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Number -> [a] -> a | Undefined + * @sig Number -> String -> String + * @param {Number} offset + * @param {*} list + * @return {*} + * @example + * + * var list = ['foo', 'bar', 'baz', 'quux']; + * R.nth(1, list); //=> 'bar' + * R.nth(-1, list); //=> 'quux' + * R.nth(-99, list); //=> undefined + * + * R.nth(2, 'abc'); //=> 'c' + * R.nth(3, 'abc'); //=> '' + * @symb R.nth(-1, [a, b, c]) = c + * @symb R.nth(0, [a, b, c]) = a + * @symb R.nth(1, [a, b, c]) = b + */ +var nth = /*#__PURE__*/_curry2(function nth(offset, list) { + var idx = offset < 0 ? list.length + offset : offset; + return _isString(list) ? list.charAt(idx) : list[idx]; +}); + +/** + * Returns the last element of the given list or string. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.init, R.head, R.tail + * @example + * + * R.last(['fi', 'fo', 'fum']); //=> 'fum' + * R.last([]); //=> undefined + * + * R.last('abc'); //=> 'c' + * R.last(''); //=> '' + */ +var last = /*#__PURE__*/nth(-1); + +/** + * Returns a new list without any consecutively repeating elements. Equality is + * determined by applying the supplied predicate to each pair of consecutive elements. The + * first element in a series of equal elements will be preserved. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.14.0 + * @category List + * @sig ((a, a) -> Boolean) -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @see R.transduce + * @example + * + * var l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3]; + * R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3] + */ +var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) { + var result = []; + var idx = 1; + var len = list.length; + if (len !== 0) { + result[0] = list[0]; + while (idx < len) { + if (!pred(last(result), list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + } + return result; +})); + +/** + * Returns a new list without any consecutively repeating elements. + * [`R.equals`](#equals) is used to determine equality. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.14.0 + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @see R.transduce + * @example + * + * R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2] + */ +var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals))); + +/** + * Returns the empty value of its argument's type. Ramda defines the empty + * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other + * types are supported if they define `.empty`, + * `.prototype.empty` or implement the + * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid). + * + * Dispatches to the `empty` method of the first argument, if present. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category Function + * @sig a -> a + * @param {*} x + * @return {*} + * @example + * + * R.empty(Just(42)); //=> Nothing() + * R.empty([1, 2, 3]); //=> [] + * R.empty('unicorns'); //=> '' + * R.empty({x: 1, y: 2}); //=> {} + */ +var empty = /*#__PURE__*/_curry1(function empty(x) { + return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () { + return arguments; + }() : + // else + void 0; +}); + +/** + * Returns a new function much like the supplied one, except that the first two + * arguments' order is reversed. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z) + * @param {Function} fn The function to invoke with its first two parameters reversed. + * @return {*} The result of invoking `fn` with its first two parameters' order reversed. + * @example + * + * var mergeThree = (a, b, c) => [].concat(a, b, c); + * + * mergeThree(1, 2, 3); //=> [1, 2, 3] + * + * R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3] + * @symb R.flip(f)(a, b, c) = f(b, a, c) + */ +var flip = /*#__PURE__*/_curry1(function flip(fn) { + return curryN(fn.length, function (a, b) { + var args = Array.prototype.slice.call(arguments, 0); + args[0] = b; + args[1] = a; + return fn.apply(this, args); + }); +}); + +/** + * Iterate over an input `list`, calling a provided function `fn` for each + * element in the list. + * + * `fn` receives one argument: *(value)*. + * + * Note: `R.forEach` does not skip deleted or unassigned indices (sparse + * arrays), unlike the native `Array.prototype.forEach` method. For more + * details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description + * + * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns + * the original array. In some libraries this function is named `each`. + * + * Dispatches to the `forEach` method of the second argument, if present. + * + * @func + * @memberOf R + * @since v0.1.1 + * @category List + * @sig (a -> *) -> [a] -> [a] + * @param {Function} fn The function to invoke. Receives one argument, `value`. + * @param {Array} list The list to iterate over. + * @return {Array} The original list. + * @see R.addIndex + * @example + * + * var printXPlusFive = x => console.log(x + 5); + * R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3] + * // logs 6 + * // logs 7 + * // logs 8 + * @symb R.forEach(f, [a, b, c]) = [a, b, c] + */ +var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) { + var len = list.length; + var idx = 0; + while (idx < len) { + fn(list[idx]); + idx += 1; + } + return list; +})); + +/** + * Iterate over an input `object`, calling a provided function `fn` for each + * key and value in the object. + * + * `fn` receives three argument: *(value, key, obj)*. + * + * @func + * @memberOf R + * @since v0.23.0 + * @category Object + * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a + * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`. + * @param {Object} obj The object to iterate over. + * @return {Object} The original object. + * @example + * + * var printKeyConcatValue = (value, key) => console.log(key + ':' + value); + * R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2} + * // logs x:1 + * // logs y:2 + * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b} + */ +var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) { + var keyList = keys(obj); + var idx = 0; + while (idx < keyList.length) { + var key = keyList[idx]; + fn(obj[key], key, obj); + idx += 1; + } + return obj; +}); + +/** + * Splits a list into sub-lists stored in an object, based on the result of + * calling a String-returning function on each element, and grouping the + * results according to values returned. + * + * Dispatches to the `groupBy` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig (a -> String) -> [a] -> {String: [a]} + * @param {Function} fn Function :: a -> String + * @param {Array} list The array to group + * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements + * that produced that key when passed to `fn`. + * @see R.transduce + * @example + * + * var byGrade = R.groupBy(function(student) { + * var score = student.score; + * return score < 65 ? 'F' : + * score < 70 ? 'D' : + * score < 80 ? 'C' : + * score < 90 ? 'B' : 'A'; + * }); + * var students = [{name: 'Abby', score: 84}, + * {name: 'Eddy', score: 58}, + * // ... + * {name: 'Jack', score: 69}]; + * byGrade(students); + * // { + * // 'A': [{name: 'Dianne', score: 99}], + * // 'B': [{name: 'Abby', score: 84}] + * // // ..., + * // 'F': [{name: 'Eddy', score: 58}] + * // } + */ +var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) { + if (acc == null) { + acc = []; + } + acc.push(item); + return acc; +}, null))); + +/** + * Returns the first element of the given list or string. In some libraries + * this function is named `first`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {Array|String} list + * @return {*} + * @see R.tail, R.init, R.last + * @example + * + * R.head(['fi', 'fo', 'fum']); //=> 'fi' + * R.head([]); //=> undefined + * + * R.head('abc'); //=> 'a' + * R.head(''); //=> '' + */ +var head = /*#__PURE__*/nth(0); + +function _identity(x) { + return x; +} + +/** + * A function that does nothing but return the parameter supplied to it. Good + * as a default or placeholder function. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig a -> a + * @param {*} x The value to return. + * @return {*} The input value, `x`. + * @example + * + * R.identity(1); //=> 1 + * + * var obj = {}; + * R.identity(obj) === obj; //=> true + * @symb R.identity(a) = a + */ +var identity = /*#__PURE__*/_curry1(_identity); + +/** + * Increments its argument. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} n + 1 + * @see R.dec + * @example + * + * R.inc(42); //=> 43 + */ +var inc = /*#__PURE__*/add(1); + +/** + * Given a function that generates a key, turns a list of objects into an + * object indexing the objects by the given key. Note that if multiple + * objects generate the same value for the indexing key only the last value + * will be included in the generated object. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category List + * @sig (a -> String) -> [{k: v}] -> {k: {k: v}} + * @param {Function} fn Function :: a -> String + * @param {Array} array The array of objects to index + * @return {Object} An object indexing each array element by the given property. + * @example + * + * var list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}]; + * R.indexBy(R.prop('id'), list); + * //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}} + */ +var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) { + return elem; +}, null); + +/** + * Returns all but the last element of the given list or string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.last, R.head, R.tail + * @example + * + * R.init([1, 2, 3]); //=> [1, 2] + * R.init([1, 2]); //=> [1] + * R.init([1]); //=> [] + * R.init([]); //=> [] + * + * R.init('abc'); //=> 'ab' + * R.init('ab'); //=> 'a' + * R.init('a'); //=> '' + * R.init(''); //=> '' + */ +var init = /*#__PURE__*/slice(0, -1); + +var _Set = /*#__PURE__*/function () { + function _Set() { + /* globals Set */ + this._nativeSet = typeof Set === 'function' ? new Set() : null; + this._items = {}; + } + + // until we figure out why jsdoc chokes on this + // @param item The item to add to the Set + // @returns {boolean} true if the item did not exist prior, otherwise false + // + _Set.prototype.add = function (item) { + return !hasOrAdd(item, true, this); + }; + + // + // @param item The item to check for existence in the Set + // @returns {boolean} true if the item exists in the Set, otherwise false + // + _Set.prototype.has = function (item) { + return hasOrAdd(item, false, this); + }; + + // + // Combines the logic for checking whether an item is a member of the set and + // for adding a new item to the set. + // + // @param item The item to check or add to the Set instance. + // @param shouldAdd If true, the item will be added to the set if it doesn't + // already exist. + // @param set The set instance to check or add to. + // @return {boolean} true if the item already existed, otherwise false. + // + return _Set; +}(); + +function hasOrAdd(item, shouldAdd, set) { + var type = typeof item; + var prevSize, newSize; + switch (type) { + case 'string': + case 'number': + // distinguish between +0 and -0 + if (item === 0 && 1 / item === -Infinity) { + if (set._items['-0']) { + return true; + } else { + if (shouldAdd) { + set._items['-0'] = true; + } + return false; + } + } + // these types can all utilise the native Set + if (set._nativeSet !== null) { + if (shouldAdd) { + prevSize = set._nativeSet.size; + set._nativeSet.add(item); + newSize = set._nativeSet.size; + return newSize === prevSize; + } else { + return set._nativeSet.has(item); + } + } else { + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = {}; + set._items[type][item] = true; + } + return false; + } else if (item in set._items[type]) { + return true; + } else { + if (shouldAdd) { + set._items[type][item] = true; + } + return false; + } + } + + case 'boolean': + // set._items['boolean'] holds a two element array + // representing [ falseExists, trueExists ] + if (type in set._items) { + var bIdx = item ? 1 : 0; + if (set._items[type][bIdx]) { + return true; + } else { + if (shouldAdd) { + set._items[type][bIdx] = true; + } + return false; + } + } else { + if (shouldAdd) { + set._items[type] = item ? [false, true] : [true, false]; + } + return false; + } + + case 'function': + // compare functions for reference equality + if (set._nativeSet !== null) { + if (shouldAdd) { + prevSize = set._nativeSet.size; + set._nativeSet.add(item); + newSize = set._nativeSet.size; + return newSize === prevSize; + } else { + return set._nativeSet.has(item); + } + } else { + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = [item]; + } + return false; + } + if (!_contains(item, set._items[type])) { + if (shouldAdd) { + set._items[type].push(item); + } + return false; + } + return true; + } + + case 'undefined': + if (set._items[type]) { + return true; + } else { + if (shouldAdd) { + set._items[type] = true; + } + return false; + } + + case 'object': + if (item === null) { + if (!set._items['null']) { + if (shouldAdd) { + set._items['null'] = true; + } + return false; + } + return true; + } + /* falls through */ + default: + // reduce the search size of heterogeneous sets by creating buckets + // for each type. + type = Object.prototype.toString.call(item); + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = [item]; + } + return false; + } + // scan through all previously applied items + if (!_contains(item, set._items[type])) { + if (shouldAdd) { + set._items[type].push(item); + } + return false; + } + return true; + } +} + +/** + * Returns a new list containing only one copy of each element in the original + * list, based upon the value returned by applying the supplied function to + * each list element. Prefers the first item if the supplied function produces + * the same value on two items. [`R.equals`](#equals) is used for comparison. + * + * @func + * @memberOf R + * @since v0.16.0 + * @category List + * @sig (a -> b) -> [a] -> [a] + * @param {Function} fn A function used to produce a value to use during comparisons. + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10] + */ +var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) { + var set = new _Set(); + var result = []; + var idx = 0; + var appliedItem, item; + + while (idx < list.length) { + item = list[idx]; + appliedItem = fn(item); + if (set.add(appliedItem)) { + result.push(item); + } + idx += 1; + } + return result; +}); + +/** + * Returns a new list containing only one copy of each element in the original + * list. [`R.equals`](#equals) is used to determine equality. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniq([1, 1, 2, 1]); //=> [1, 2] + * R.uniq([1, '1']); //=> [1, '1'] + * R.uniq([[42], [42]]); //=> [[42]] + */ +var uniq = /*#__PURE__*/uniqBy(identity); + +/** + * Turns a named method with a specified arity into a function that can be + * called directly supplied with arguments and a target object. + * + * The returned function is curried and accepts `arity + 1` parameters where + * the final parameter is the target object. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *) + * @param {Number} arity Number of arguments the returned function should take + * before the target object. + * @param {String} method Name of the method to call. + * @return {Function} A new curried function. + * @see R.construct + * @example + * + * var sliceFrom = R.invoker(1, 'slice'); + * sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm' + * var sliceFrom6 = R.invoker(2, 'slice')(6); + * sliceFrom6(8, 'abcdefghijklm'); //=> 'gh' + * @symb R.invoker(0, 'method')(o) = o['method']() + * @symb R.invoker(1, 'method')(a, o) = o['method'](a) + * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b) + */ +var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) { + return curryN(arity + 1, function () { + var target = arguments[arity]; + if (target != null && _isFunction(target[method])) { + return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity)); + } + throw new TypeError(toString$1(target) + ' does not have a method named "' + method + '"'); + }); +}); + +/** + * Returns `true` if the given value is its type's empty value; `false` + * otherwise. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Logic + * @sig a -> Boolean + * @param {*} x + * @return {Boolean} + * @see R.empty + * @example + * + * R.isEmpty([1, 2, 3]); //=> false + * R.isEmpty([]); //=> true + * R.isEmpty(''); //=> true + * R.isEmpty(null); //=> false + * R.isEmpty({}); //=> true + * R.isEmpty({length: 0}); //=> false + */ +var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) { + return x != null && equals(x, empty(x)); +}); + +/** + * Returns a string made by inserting the `separator` between each element and + * concatenating all the elements into a single string. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig String -> [a] -> String + * @param {Number|String} separator The string used to separate the elements. + * @param {Array} xs The elements to join into a string. + * @return {String} str The string made by concatenating `xs` with `separator`. + * @see R.split + * @example + * + * var spacer = R.join(' '); + * spacer(['a', 2, 3.4]); //=> 'a 2 3.4' + * R.join('|', [1, 2, 3]); //=> '1|2|3' + */ +var join = /*#__PURE__*/invoker(1, 'join'); + +/** + * juxt applies a list of functions to a list of values. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Function + * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n]) + * @param {Array} fns An array of functions + * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters. + * @see R.applySpec + * @example + * + * var getRange = R.juxt([Math.min, Math.max]); + * getRange(3, 4, 9, -3); //=> [-3, 9] + * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)] + */ +var juxt = /*#__PURE__*/_curry1(function juxt(fns) { + return converge(function () { + return Array.prototype.slice.call(arguments, 0); + }, fns); +}); + +function _isNumber(x) { + return Object.prototype.toString.call(x) === '[object Number]'; +} + +/** + * Returns the number of elements in the array by returning `list.length`. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig [a] -> Number + * @param {Array} list The array to inspect. + * @return {Number} The length of the array. + * @example + * + * R.length([]); //=> 0 + * R.length([1, 2, 3]); //=> 3 + */ +var length = /*#__PURE__*/_curry1(function length(list) { + return list != null && _isNumber(list.length) ? list.length : NaN; +}); + +/** + * Adds together all the elements of a list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The sum of all the numbers in the list. + * @see R.reduce + * @example + * + * R.sum([2,4,6,8,100,1]); //=> 121 + */ +var sum = /*#__PURE__*/reduce(add, 0); + +/** + * A customisable version of [`R.memoize`](#memoize). `memoizeWith` takes an + * additional function that will be applied to a given argument set and used to + * create the cache key under which the results of the function to be memoized + * will be stored. Care must be taken when implementing key generation to avoid + * clashes that may overwrite previous entries erroneously. + * + * + * @func + * @memberOf R + * @since v0.24.0 + * @category Function + * @sig (*... -> String) -> (*... -> a) -> (*... -> a) + * @param {Function} fn The function to generate the cache key. + * @param {Function} fn The function to memoize. + * @return {Function} Memoized version of `fn`. + * @see R.memoize + * @example + * + * let count = 0; + * const factorial = R.memoizeWith(R.identity, n => { + * count += 1; + * return R.product(R.range(1, n + 1)); + * }); + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * count; //=> 1 + */ +var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) { + var cache = {}; + return _arity(fn.length, function () { + var key = mFn.apply(this, arguments); + if (!_has(key, cache)) { + cache[key] = fn.apply(this, arguments); + } + return cache[key]; + }); +}); + +/** + * Creates a new function that, when invoked, caches the result of calling `fn` + * for a given argument set and returns the result. Subsequent calls to the + * memoized `fn` with the same argument set will not result in an additional + * call to `fn`; instead, the cached result for that set of arguments will be + * returned. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (*... -> a) -> (*... -> a) + * @param {Function} fn The function to memoize. + * @return {Function} Memoized version of `fn`. + * @see R.memoizeWith + * @deprecated since v0.25.0 + * @example + * + * let count = 0; + * const factorial = R.memoize(n => { + * count += 1; + * return R.product(R.range(1, n + 1)); + * }); + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * count; //=> 1 + */ +var memoize = /*#__PURE__*/memoizeWith(function () { + return toString$1(arguments); +}); + +/** + * Creates a new object with the own properties of the two provided objects. If + * a key exists in both objects, the provided function is applied to the key + * and the values associated with the key in each object, with the result being + * used as the value associated with the key in the returned object. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Object + * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a} + * @param {Function} fn + * @param {Object} l + * @param {Object} r + * @return {Object} + * @see R.mergeDeepWithKey, R.merge, R.mergeWith + * @example + * + * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r + * R.mergeWithKey(concatValues, + * { a: true, thing: 'foo', values: [10, 20] }, + * { b: true, thing: 'bar', values: [15, 35] }); + * //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] } + * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 } + */ +var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) { + var result = {}; + var k; + + for (k in l) { + if (_has(k, l)) { + result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k]; + } + } + + for (k in r) { + if (_has(k, r) && !_has(k, result)) { + result[k] = r[k]; + } + } + + return result; +}); + +/** + * Creates a new object with the own properties of the two provided objects. If + * a key exists in both objects, the provided function is applied to the values + * associated with the key in each object, with the result being used as the + * value associated with the key in the returned object. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Object + * @sig ((a, a) -> a) -> {a} -> {a} -> {a} + * @param {Function} fn + * @param {Object} l + * @param {Object} r + * @return {Object} + * @see R.mergeDeepWith, R.merge, R.mergeWithKey + * @example + * + * R.mergeWith(R.concat, + * { a: true, values: [10, 20] }, + * { b: true, values: [15, 35] }); + * //=> { a: true, b: true, values: [10, 20, 15, 35] } + */ +var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) { + return mergeWithKey(function (_, _l, _r) { + return fn(_l, _r); + }, l, r); +}); + +/** + * Multiplies two numbers. Equivalent to `a * b` but curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The first value. + * @param {Number} b The second value. + * @return {Number} The result of `a * b`. + * @see R.divide + * @example + * + * var double = R.multiply(2); + * var triple = R.multiply(3); + * double(3); //=> 6 + * triple(4); //=> 12 + * R.multiply(2, 5); //=> 10 + */ +var multiply = /*#__PURE__*/_curry2(function multiply(a, b) { + return a * b; +}); + +function _createPartialApplicator(concat) { + return _curry2(function (fn, args) { + return _arity(Math.max(0, fn.length - args.length), function () { + return fn.apply(this, concat(args, arguments)); + }); + }); +} + +/** + * Takes a function `f` and a list of arguments, and returns a function `g`. + * When applied, `g` returns the result of applying `f` to the arguments + * provided to `g` followed by the arguments provided initially. + * + * @func + * @memberOf R + * @since v0.10.0 + * @category Function + * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x) + * @param {Function} f + * @param {Array} args + * @return {Function} + * @see R.partial + * @example + * + * var greet = (salutation, title, firstName, lastName) => + * salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; + * + * var greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']); + * + * greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!' + * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b) + */ +var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat)); + +/** + * Takes a predicate and a list or other `Filterable` object and returns the + * pair of filterable objects of the same type of elements which do and do not + * satisfy, the predicate, respectively. Filterable objects include plain objects or any object + * that has a filter method such as `Array`. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a] + * @param {Function} pred A predicate to determine which side the element belongs to. + * @param {Array} filterable the list (or other filterable) to partition. + * @return {Array} An array, containing first the subset of elements that satisfy the + * predicate, and second the subset of elements that do not satisfy. + * @see R.filter, R.reject + * @example + * + * R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); + * // => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] + * + * R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' }); + * // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ] + */ +var partition = /*#__PURE__*/juxt([filter, reject]); + +/** + * Similar to `pick` except that this one includes a `key: undefined` pair for + * properties that don't exist. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig [k] -> {k: v} -> {k: v} + * @param {Array} names an array of String property names to copy onto a new object + * @param {Object} obj The object to copy from + * @return {Object} A new object with only properties from `names` on it. + * @see R.pick + * @example + * + * R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} + * R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined} + */ +var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) { + var result = {}; + var idx = 0; + var len = names.length; + while (idx < len) { + var name = names[idx]; + result[name] = obj[name]; + idx += 1; + } + return result; +}); + +/** + * Multiplies together all the elements of a list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The product of all the numbers in the list. + * @see R.reduce + * @example + * + * R.product([2,4,6,8,100,1]); //=> 38400 + */ +var product = /*#__PURE__*/reduce(multiply, 1); + +/** + * Accepts a function `fn` and a list of transformer functions and returns a + * new curried function. When the new function is invoked, it calls the + * function `fn` with parameters consisting of the result of calling each + * supplied handler on successive arguments to the new function. + * + * If more arguments are passed to the returned function than transformer + * functions, those arguments are passed directly to `fn` as additional + * parameters. If you expect additional arguments that don't need to be + * transformed, although you can ignore them, it's best to pass an identity + * function so that the new function reports the correct arity. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z) + * @param {Function} fn The function to wrap. + * @param {Array} transformers A list of transformer functions + * @return {Function} The wrapped function. + * @see R.converge + * @example + * + * R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81 + * R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81 + * R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32 + * R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32 + * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b)) + */ +var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) { + return curryN(transformers.length, function () { + var args = []; + var idx = 0; + while (idx < transformers.length) { + args.push(transformers[idx].call(this, arguments[idx])); + idx += 1; + } + return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length))); + }); +}); + +/** + * Reasonable analog to SQL `select` statement. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @category Relation + * @sig [k] -> [{k: v}] -> [{k: v}] + * @param {Array} props The property names to project + * @param {Array} objs The objects to query + * @return {Array} An array of objects with just the `props` properties. + * @example + * + * var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}; + * var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}; + * var kids = [abby, fred]; + * R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}] + */ +var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity + +/** + * Returns a copy of the list, sorted according to the comparator function, + * which should accept two values at a time and return a negative number if the + * first value is smaller, a positive number if it's larger, and zero if they + * are equal. Please note that this is a **copy** of the list. It does not + * modify the original. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig ((a, a) -> Number) -> [a] -> [a] + * @param {Function} comparator A sorting function :: a -> b -> Int + * @param {Array} list The list to sort + * @return {Array} a new array with its elements sorted by the comparator function. + * @example + * + * var diff = function(a, b) { return a - b; }; + * R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7] + */ +var sort = /*#__PURE__*/_curry2(function sort(comparator, list) { + return Array.prototype.slice.call(list, 0).sort(comparator); +}); + +/** + * Splits a string into an array of strings based on the given + * separator. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category String + * @sig (String | RegExp) -> String -> [String] + * @param {String|RegExp} sep The pattern. + * @param {String} str The string to separate into an array. + * @return {Array} The array of strings from `str` separated by `str`. + * @see R.join + * @example + * + * var pathComponents = R.split('/'); + * R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node'] + * + * R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd'] + */ +var split = /*#__PURE__*/invoker(1, 'split'); + +/** + * The lower case version of a string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category String + * @sig String -> String + * @param {String} str The string to lower case. + * @return {String} The lower case version of `str`. + * @see R.toUpper + * @example + * + * R.toLower('XYZ'); //=> 'xyz' + */ +var toLower = /*#__PURE__*/invoker(0, 'toLowerCase'); + +/** + * Converts an object into an array of key, value arrays. Only the object's + * own properties are used. + * Note that the order of the output array is not guaranteed to be consistent + * across different JS platforms. + * + * @func + * @memberOf R + * @since v0.4.0 + * @category Object + * @sig {String: *} -> [[String,*]] + * @param {Object} obj The object to extract from + * @return {Array} An array of key, value arrays from the object's own properties. + * @see R.fromPairs + * @example + * + * R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]] + */ +var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) { + var pairs = []; + for (var prop in obj) { + if (_has(prop, obj)) { + pairs[pairs.length] = [prop, obj[prop]]; + } + } + return pairs; +}); + +/** + * The upper case version of a string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category String + * @sig String -> String + * @param {String} str The string to upper case. + * @return {String} The upper case version of `str`. + * @see R.toLower + * @example + * + * R.toUpper('abc'); //=> 'ABC' + */ +var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase'); + +/** + * Initializes a transducer using supplied iterator function. Returns a single + * item by iterating through the list, successively calling the transformed + * iterator function and passing it an accumulator value and the current value + * from the array, and then passing the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It will be + * wrapped as a transformer to initialize the transducer. A transformer can be + * passed directly in place of an iterator function. In both cases, iteration + * may be stopped early with the [`R.reduced`](#reduced) function. + * + * A transducer is a function that accepts a transformer and returns a + * transformer and can be composed directly. + * + * A transformer is an an object that provides a 2-arity reducing iterator + * function, step, 0-arity initial value function, init, and 1-arity result + * extraction function, result. The step function is used as the iterator + * function in reduce. The result function is used to convert the final + * accumulator into the return type and in most cases is + * [`R.identity`](#identity). The init function can be used to provide an + * initial accumulator, but is ignored by transduce. + * + * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer. + * + * @func + * @memberOf R + * @since v0.12.0 + * @category List + * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a + * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. Wrapped as transformer, if necessary, and used to + * initialize the transducer + * @param {*} acc The initial accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @see R.reduce, R.reduced, R.into + * @example + * + * var numbers = [1, 2, 3, 4]; + * var transducer = R.compose(R.map(R.add(1)), R.take(2)); + * R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3] + * + * var isOdd = (x) => x % 2 === 1; + * var firstOddTransducer = R.compose(R.filter(isOdd), R.take(1)); + * R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1] + */ +var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) { + return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list); +}); + +var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; +var zeroWidth = '\u200b'; +var hasProtoTrim = typeof String.prototype.trim === 'function'; +/** + * Removes (strips) whitespace from both ends of the string. + * + * @func + * @memberOf R + * @since v0.6.0 + * @category String + * @sig String -> String + * @param {String} str The string to trim. + * @return {String} Trimmed version of `str`. + * @example + * + * R.trim(' xyz '); //=> 'xyz' + * R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z'] + */ +var _trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? function trim(str) { + var beginRx = new RegExp('^[' + ws + '][' + ws + ']*'); + var endRx = new RegExp('[' + ws + '][' + ws + ']*$'); + return str.replace(beginRx, '').replace(endRx, ''); +} : function trim(str) { + return str.trim(); +}; + +/** + * Combines two lists into a set (i.e. no duplicates) composed of the elements + * of each list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig [*] -> [*] -> [*] + * @param {Array} as The first list. + * @param {Array} bs The second list. + * @return {Array} The first and second lists concatenated, with + * duplicates removed. + * @example + * + * R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4] + */ +var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat)); + +/** + * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from + * any [Chain](https://github.com/fantasyland/fantasy-land#chain). + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig Chain c => c (c a) -> c a + * @param {*} list + * @return {*} + * @see R.flatten, R.chain + * @example + * + * R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]] + * R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6] + */ +var unnest = /*#__PURE__*/chain(_identity); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + + + + + + + + + + + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); + + + + + +var defineProperty = function (obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; +}; + +var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + + + + + + + + + + + + + +var objectWithoutProperties = function (obj, keys) { + var target = {}; + + for (var i in obj) { + if (keys.indexOf(i) >= 0) continue; + if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; + target[i] = obj[i]; + } + + return target; +}; + + + + + + + +var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +}(); + +// urlEncode :: Object -> String +var urlEncode = pipe(filter(function (x) { + return x !== undefined; +}), toPairs, map(function (_ref) { + var _ref2 = slicedToArray(_ref, 2), + k = _ref2[0], + v = _ref2[1]; + + return k + '=' + encodeURIComponent(v); +}), join('&')); + +// appendQueryParam :: String -> String -> String -> String +var appendQueryParam = function appendQueryParam(key, value, url) { + var _split = split('?', url), + _split2 = slicedToArray(_split, 2), + before = _split2[0], + after = _split2[1]; + + return before + '?' + (after ? after + '&' : '') + urlEncode(defineProperty({}, key, value)); +}; + +var typeCheck = function typeCheck(name, expectedType, value) { + var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); + if (type !== expectedType) { + throw new TypeError('expected ' + name + ' to be of type ' + expectedType + ' but was of type ' + type); + } +}; + +// checks that all of an arrays elements are of the given type +var typeCheckArr = function typeCheckArr(name, expectedType, arr) { + if (!Array.isArray(arr)) { + throw new TypeError('expected ' + name + ' to be an array'); + } + arr.forEach(function (value, i) { + return typeCheck(name + '[' + i + ']', expectedType, value); + }); +}; + +// checks that all of an objects values are of the given type +var typeCheckObj = function typeCheckObj(name, expectedType, obj) { + typeCheck(name, 'object', obj); + forEachObjIndexed(function (value, key) { + return typeCheck(key, expectedType, value); + }, obj); +}; + +var checkOneOf = function checkOneOf(name, values, value) { + if (!contains$1(value, values)) { + throw new TypeError('expected ' + name + ' to be one of ' + values + ' but was ' + value); + } +}; + +// pointfree debugging + +var TokenProvider = +// TODO authContext +function TokenProvider() { + var _this = this; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + url = _ref.url; + + classCallCheck(this, TokenProvider); + + this.fetchToken = function () { + return pusherPlatform_4({ + body: urlEncode({ grant_type: 'client_credentials' }), + headers: { + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + url: appendQueryParam('user_id', _this.userId, _this.url) + }).then(function (res) { + return JSON.parse(res).access_token; + }); + }; + + this.setUserId = function (userId) { + _this.userId = userId; + }; + + typeCheck('url', 'string', url); + this.url = url; +}; + +var Store = function Store() { + var _this = this; + + classCallCheck(this, Store); + this.pendingSets = []; + this.pendingGets = []; + + this.initialize = function (initialStore) { + _this.store = clone(initialStore); + forEach(function (_ref) { + var key = _ref.key, + value = _ref.value, + resolve = _ref.resolve; + + resolve(_this.store[key] = value); + }, _this.pendingSets); + forEach(function (_ref2) { + var key = _ref2.key, + resolve = _ref2.resolve; + + resolve(_this.store[key]); + }, _this.pendingGets); + }; + + this.set = function (key, value) { + if (_this.store) { + return Promise.resolve(_this.store[key] = value); + } else { + return new Promise(function (resolve) { + _this.pendingSets.push({ key: key, value: value, resolve: resolve }); + }); + } + }; + + this.get = function (key) { + if (_this.store) { + return Promise.resolve(_this.store[key]); + } else { + return new Promise(function (resolve) { + _this.pendingGets.push({ key: key, resolve: resolve }); + }); + } + }; + + this.pop = function (key) { + return _this.get(key).then(function (value) { + delete _this.store[key]; + return value; + }); + }; + + this.snapshot = function () { + return _this.store || {}; + }; + + this.getSync = function (key) { + return _this.store ? _this.store[key] : undefined; + }; +}; + +var parseBasicRoom = function parseBasicRoom(data) { + return { + createdAt: data.created_at, + createdByUserId: data.created_by_id, + deletedAt: data.deletedAt, + id: data.id, + isPrivate: data.private, + name: data.name, + updatedAt: data.updated_at, + userIds: data.member_user_ids + }; +}; + +var parseUser = function parseUser(data) { + return { + avatarURL: data.avatar_url, + createdAt: data.created_at, + customData: data.custom_data, + id: data.id, + name: data.name, + updatedAt: data.updated_at + }; +}; + +var parsePresence = function parsePresence(data) { + return { + lastSeenAt: data.last_seen_at, + state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', + userId: data.user_id + }; +}; + +var parseBasicMessage = function parseBasicMessage(data) { + return { + id: data.id, + senderId: data.user_id, + roomId: data.room_id, + text: data.text, + createdAt: data.created_at, + updatedAt: data.updated_at + }; +}; + +var UserStore = function UserStore(_ref) { + var _this = this; + + var instance = _ref.instance, + presenceStore = _ref.presenceStore, + logger = _ref.logger; + classCallCheck(this, UserStore); + this.store = new Store(); + this.initialize = this.store.initialize; + this.set = this.store.set; + + this.get = function (userId) { + return Promise.all([_this.store.get(userId).then(function (user) { + return user || _this.fetchBasicUser(userId); + }), _this.presenceStore.get(userId)]).then(function (_ref2) { + var _ref3 = slicedToArray(_ref2, 2), + user = _ref3[0], + presence = _ref3[1]; + + return _extends({}, user, { presence: presence }); + }); + }; + + this.fetchBasicUser = function (userId) { + return _this.instance.request({ + method: 'GET', + path: '/users/' + userId + }).then(function (res) { + var user = parseUser(JSON.parse(res)); + _this.set(userId, user); + return user; + }).catch(function (err) { + _this.logger.warn('error fetching user information:', err); + throw err; + }); + }; + + this.fetchMissingUsers = function (userIds) { + var missing = difference(userIds, map(prop('id'), values(_this.store.snapshot()))); + if (length(missing) === 0) { + return Promise.resolve(); + } + // TODO don't make simulatneous requests for the same users + return _this.instance.request({ + method: 'GET', + path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') + }).then(pipe(JSON.parse, map(parseUser), forEach(function (user) { + return _this.set(user.id, user); + }))).catch(function (err) { + _this.logger.warn('error fetching missing users:', err); + throw err; + }); + }; + + this.snapshot = function () { + return map(_this.decorate, _this.store.snapshot()); + }; + + this.getSync = function (userId) { + return _this.decorate(_this.store.getSync(userId)); + }; + + this.decorate = function (user) { + return user ? _extends({}, user, { presence: _this.presenceStore.getSync(user.id) }) : undefined; + }; + + this.instance = instance; + this.presenceStore = presenceStore; + this.logger = logger; +}; + +var Room = function () { + function Room(basicRoom, userStore) { + classCallCheck(this, Room); + + this.createdAt = basicRoom.createdAt; + this.createdByUserId = basicRoom.createdByUserId; + this.deletedAt = basicRoom.deletedAt; + this.id = basicRoom.id; + this.isPrivate = basicRoom.isPrivate; + this.name = basicRoom.name; + this.updatedAt = basicRoom.updatedAt; + this.userIds = basicRoom.userIds; + this.userStore = userStore; + } + + createClass(Room, [{ + key: 'users', + get: function get$$1() { + var _this = this; + + return filter(function (user) { + return contains$1(user.id, _this.userIds); + }, values(this.userStore.snapshot())); + } + }]); + return Room; +}(); + +var RoomStore = function RoomStore(_ref) { + var _this = this; + + var instance = _ref.instance, + userStore = _ref.userStore, + logger = _ref.logger; + classCallCheck(this, RoomStore); + this.store = new Store(); + this.initialize = this.store.initialize; + this.set = curry(function (roomId, basicRoom) { + return _this.store.set(roomId, basicRoom).then(_this.decorate).then(function (room) { + return _this.userStore.fetchMissingUsers(room.userIds).then(function () { + return room; + }); + }); + }); + + this.get = function (roomId) { + return _this.store.get(roomId).then(function (basicRoom) { + return basicRoom || _this.fetchBasicRoom(roomId).then(_this.set(roomId)); + }).then(_this.decorate); + }; + + this.pop = function (roomId) { + return _this.store.pop(roomId).then(function (basicRoom) { + return basicRoom || _this.fetchBasicRoom(roomId); + }).then(_this.decorate); + }; + + this.addUserToRoom = function (roomId, userId) { + return _this.pop(roomId).then(function (r) { + return _this.set(roomId, _extends({}, r, { userIds: uniq(append(userId, r.userIds)) })); + }); + }; + + this.removeUserFromRoom = function (roomId, userId) { + return _this.pop(roomId).then(function (r) { + return _this.set(roomId, _extends({}, r, { userIds: filter(function (id) { + return id !== userId; + }, r.userIds) })); + }); + }; + + this.update = function (roomId, updates) { + return _this.store.pop(roomId).then(function (r) { + return _this.set(roomId, mergeWith(function (x, y) { + return y || x; + }, r, updates)); + }); + }; + + this.fetchBasicRoom = function (roomId) { + return _this.instance.request({ + method: 'GET', + path: '/rooms/' + roomId + }).then(pipe(JSON.parse, parseBasicRoom)).catch(function (err) { + _this.logger.warn('error fetching details for room ' + roomId + ':', err); + }); + }; + + this.snapshot = function () { + return map(_this.decorate, _this.store.snapshot()); + }; + + this.getSync = function (roomId) { + return _this.decorate(_this.store.getSync(roomId)); + }; + + this.decorate = function (basicRoom) { + return basicRoom ? new Room(basicRoom, _this.userStore) : undefined; + }; + + this.instance = instance; + this.userStore = userStore; + this.logger = logger; +}; + +var TYPING_INDICATOR_TTL = 1500; +var TYPING_INDICATOR_LEEWAY = 500; + +var TypingIndicators = function TypingIndicators(_ref) { + var _this = this; + + var userId = _ref.userId, + instance = _ref.instance, + logger = _ref.logger; + classCallCheck(this, TypingIndicators); + + this.sendThrottledRequest = function (roomId) { + var now = Date.now(); + var sent = _this.lastSentRequests[roomId]; + if (sent && now - sent < TYPING_INDICATOR_TTL - TYPING_INDICATOR_LEEWAY) { + return Promise.resolve(); + } + _this.lastSentRequests[roomId] = now; + return _this.instance.request({ + method: 'POST', + path: '/rooms/' + roomId + '/events', + json: { + name: 'typing_start', // TODO 'is_typing' + user_id: _this.userId + } + }).catch(function (err) { + delete _this.typingRequestSent[roomId]; + _this.logger.warn('Error sending is_typing event in room ' + roomId, err); + throw err; + }); + }; + + this.onIsTyping = function (room, user, hooks, roomHooks) { + if (!_this.timers[room.id]) { + _this.timers[room.id] = {}; + } + if (_this.timers[room.id][user.id]) { + clearTimeout(_this.timers[room.id][user.id]); + } else { + _this.onStarted(room, user, hooks, roomHooks); + } + _this.timers[room.id][user.id] = setTimeout(function () { + _this.onStopped(room, user, hooks, roomHooks); + delete _this.timers[room.id][user.id]; + }, TYPING_INDICATOR_TTL); + }; + + this.onStarted = function (room, user, hooks, roomHooks) { + if (hooks.userStartedTyping) { + hooks.userStartedTyping(room, user); + } + if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { + roomHooks[room.id].userStartedTyping(user); + } + }; + + this.onStopped = function (room, user, hooks, roomHooks) { + if (hooks.userStoppedTyping) { + hooks.userStoppedTyping(room, user); + } + if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { + roomHooks[room.id].userStoppedTyping(user); + } + }; + + this.userId = userId; + this.instance = instance; + this.logger = logger; + this.lastSentRequests = {}; + this.timers = {}; +}; + +var UserSubscription = function () { + function UserSubscription(options) { + var _this = this; + + classCallCheck(this, UserSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'initial_state': + _this.onInitialState(body.data); + break; + case 'added_to_room': + _this.onAddedToRoom(body.data); + break; + case 'removed_from_room': + _this.onRemovedFromRoom(body.data); + break; + case 'user_joined': + _this.onUserJoined(body.data); + break; + case 'user_left': + _this.onUserLeft(body.data); + break; + case 'room_updated': + _this.onRoomUpdated(body.data); + break; + case 'room_deleted': + _this.onRoomDeleted(body.data); + break; + case 'typing_start': + // TODO 'is_typing' + _this.onIsTyping(body.data); + break; + } + }; + + this.onInitialState = function (_ref2) { + var userData = _ref2.current_user, + roomsData = _ref2.rooms; + + _this.hooks.subscriptionEstablished({ + user: parseUser(userData), + basicRooms: map(parseBasicRoom, roomsData) + }); + }; + + this.onAddedToRoom = function (_ref3) { + var roomData = _ref3.room; + + var basicRoom = parseBasicRoom(roomData); + _this.roomStore.set(basicRoom.id, basicRoom).then(function (room) { + if (_this.hooks.addedToRoom) { + _this.hooks.addedToRoom(room); + } + }); + }; + + this.onRemovedFromRoom = function (_ref4) { + var roomId = _ref4.room_id; + + _this.roomStore.pop(roomId).then(function (room) { + // room will be undefined if we left with leaveRoom + if (room && _this.hooks.removedFromRoom) { + _this.hooks.removedFromRoom(room); + } + }); + }; + + this.onUserJoined = function (_ref5) { + var roomId = _ref5.room_id, + userId = _ref5.user_id; + + _this.roomStore.addUserToRoom(roomId, userId).then(function (room) { + _this.userStore.get(userId).then(function (user) { + if (_this.hooks.userJoinedRoom) { + _this.hooks.userJoinedRoom(room, user); + } + if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userJoined) { + _this.roomSubscriptions[roomId].hooks.userJoined(user); + } + }); + }); + }; + + this.onUserLeft = function (_ref6) { + var roomId = _ref6.room_id, + userId = _ref6.user_id; + + _this.roomStore.removeUserFromRoom(roomId, userId).then(function (room) { + _this.userStore.get(userId).then(function (user) { + if (_this.hooks.userLeftRoom) { + _this.hooks.userLeftRoom(room, user); + } + if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userLeft) { + _this.roomSubscriptions[roomId].hooks.userLeft(user); + } + }); + }); + }; + + this.onRoomUpdated = function (_ref7) { + var roomData = _ref7.room; + + var updates = parseBasicRoom(roomData); + _this.roomStore.update(updates.id, updates).then(function (room) { + if (_this.hooks.roomUpdated) { + _this.hooks.roomUpdated(room); + } + }); + }; + + this.onRoomDeleted = function (_ref8) { + var roomId = _ref8.room_id; + + _this.roomStore.pop(roomId).then(function (room) { + if (room && _this.hooks.roomDeleted) { + _this.hooks.roomDeleted(room); + } + }); + }; + + this.onIsTyping = function (_ref9) { + var roomId = _ref9.room_id, + userId = _ref9.user_id; + + Promise.all([_this.roomStore.get(roomId), _this.userStore.get(userId)]).then(function (_ref10) { + var _ref11 = slicedToArray(_ref10, 2), + room = _ref11[0], + user = _ref11[1]; + + return _this.typingIndicators.onIsTyping(room, user, _this.hooks, map(prop('hooks'), _this.roomSubscriptions)); + }); + }; + + this.userId = options.userId; + this.hooks = options.hooks; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.typingIndicators = options.typingIndicators; + this.roomSubscriptions = options.roomSubscriptions; + } + + createClass(UserSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); + _this2.instance.subscribeNonResuming({ + path: '/users', + listeners: { + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return UserSubscription; +}(); + +var PresenceSubscription = function () { + function PresenceSubscription(options) { + var _this = this; + + classCallCheck(this, PresenceSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'initial_state': + _this.onInitialState(body.data); + break; + case 'presence_update': + _this.onPresenceUpdate(body.data); + break; + case 'join_room_presence_update': + _this.onJoinRoomPresenceUpdate(body.data); + break; + } + }; + + this.onInitialState = function (_ref2) { + var userStates = _ref2.user_states; + + _this.presenceStore.initialize(indexBy(prop('userId'), map(parsePresence, userStates))); + _this.hooks.subscriptionEstablished(); + }; + + this.onPresenceUpdate = function (data) { + var presence = parsePresence(data); + _this.presenceStore.set(presence.userId, presence).then(function (p) { + return _this.userStore.get(p.userId).then(function (user) { + switch (p.state) { + case 'online': + _this.onCameOnline(user); + break; + case 'offline': + _this.onWentOffline(user); + break; + } + }); + }); + }; + + this.onJoinRoomPresenceUpdate = function (_ref3) { + var userStates = _ref3.user_states; + return forEach(function (presence) { + return _this.presenceStore.set(presence.userId, presence); + }, map(parsePresence, userStates)); + }; + + this.onCameOnline = function (user) { + if (_this.hooks.userCameOnline) { + _this.hooks.userCameOnline(user); + } + compose(forEach(function (sub) { + return _this.roomStore.get(sub.roomId).then(function (room) { + if (contains$1(user.id, room.userIds)) { + sub.hooks.userCameOnlineInRoom(user); + } + }); + }), filter(function (sub) { + return sub.hooks.userCameOnlineInRoom !== undefined; + }), values)(_this.roomSubscriptions); + }; + + this.onWentOffline = function (user) { + if (_this.hooks.userWentOffline) { + _this.hooks.userWentOffline(user); + } + compose(forEach(function (sub) { + return _this.roomStore.get(sub.roomId).then(function (room) { + if (contains$1(user.id, room.userIds)) { + sub.hooks.userWentOfflineInRoom(user); + } + }); + }), filter(function (sub) { + return sub.hooks.userWentOfflineInRoom !== undefined; + }), values)(_this.roomSubscriptions); + }; + + this.userId = options.userId; + this.hooks = options.hooks; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.presenceStore = options.presenceStore; + this.roomSubscriptions = options.roomSubscriptions; + } + + createClass(PresenceSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); + _this2.instance.subscribeNonResuming({ + path: '/users/' + _this2.userId + '/presence', + listeners: { + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return PresenceSubscription; +}(); + +var Message = function () { + function Message(basicMessage, userStore, roomStore) { + classCallCheck(this, Message); + + this.id = basicMessage.id; + this.senderId = basicMessage.senderId; + this.roomId = basicMessage.roomId; + this.text = basicMessage.text; + this.createdAt = basicMessage.createdAt; + this.updatedAt = basicMessage.updatedAt; + this.userStore = userStore; + this.roomStore = roomStore; + } + + createClass(Message, [{ + key: "sender", + get: function get$$1() { + return this.userStore.getSync(this.senderId); + } + }, { + key: "room", + get: function get$$1() { + return this.roomStore.getSync(this.roomId); + } + }]); + return Message; +}(); + +var RoomSubscription = function () { + function RoomSubscription(options) { + var _this = this; + + classCallCheck(this, RoomSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'new_message': + _this.onNewMessage(body.data); + break; + } + }; + + this.onNewMessage = function (data) { + var pending = { + message: new Message(parseBasicMessage(data), _this.userStore, _this.roomStore), + ready: false + }; + _this.messageBuffer.push(pending); + _this.userStore.fetchMissingUsers([pending.message.senderId]).catch(function (err) { + _this.logger.error('error fetching missing user information:', err); + }).then(function () { + pending.ready = true; + _this.flushBuffer(); + }); + }; + + this.flushBuffer = function () { + while (!isEmpty(_this.messageBuffer) && head(_this.messageBuffer).ready) { + var message = _this.messageBuffer.shift().message; + if (_this.hooks.newMessage) { + _this.hooks.newMessage(message); + } + } + }; + + this.roomId = options.roomId; + this.hooks = options.hooks; + this.messageLimit = options.messageLimit; + this.userId = options.userId; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.messageBuffer = []; // { message, ready } + } + + createClass(RoomSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.instance.subscribeNonResuming({ + path: '/rooms/' + _this2.roomId + '?' + urlEncode({ + message_limit: _this2.messageLimit + }), + listeners: { + onOpen: resolve, + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return RoomSubscription; +}(); + +var CurrentUser = function () { + function CurrentUser(_ref) { + var _this = this; + + var id = _ref.id, + apiInstance = _ref.apiInstance; + classCallCheck(this, CurrentUser); + + this.isTypingIn = function (roomId) { + typeCheck('roomId', 'number', roomId); + return _this.typingIndicators.sendThrottledRequest(roomId); + }; + + this.createRoom = function () { + var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var name = _ref2.name, + addUserIds = _ref2.addUserIds, + rest = objectWithoutProperties(_ref2, ['name', 'addUserIds']); + + name && typeCheck('name', 'string', name); + addUserIds && typeCheckArr('addUserIds', 'string', addUserIds); + return _this.apiInstance.request({ + method: 'POST', + path: '/rooms', + json: { + created_by_id: _this.id, + name: name, + private: !!rest.private, // private is a reserved word in strict mode! + user_ids: addUserIds + } + }).then(function (res) { + var basicRoom = parseBasicRoom(JSON.parse(res)); + return _this.roomStore.set(basicRoom.id, basicRoom); + }).catch(function (err) { + _this.logger.warn('error creating room:', err); + throw err; + }); + }; + + this.getJoinableRooms = function () { + // TODO path friendly ids everywhere + return _this.apiInstance.request({ + method: 'GET', + path: '/users/' + _this.id + '/rooms?joinable=true' + }).then(pipe(JSON.parse, map(parseBasicRoom))).catch(function (err) { + _this.logger.warn('error getting joinable rooms:', err); + throw err; + }); + }; + + this.getAllRooms = function () { + return _this.getJoinableRooms().then(concat(_this.rooms)); + }; + + this.joinRoom = function (roomId) { + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'POST', + path: '/users/' + _this.id + '/rooms/' + roomId + '/join' + }).then(function (res) { + var basicRoom = parseBasicRoom(JSON.parse(res)); + return _this.roomStore.set(basicRoom.id, basicRoom); + }).catch(function (err) { + _this.logger.warn('error joining room ' + roomId + ':', err); + throw err; + }); + }; + + this.leaveRoom = function (roomId) { + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'POST', + path: '/users/' + _this.id + '/rooms/' + roomId + '/leave' + }).then(function () { + return _this.roomStore.pop(roomId); + }).catch(function (err) { + _this.logger.warn('error joining room ' + roomId + ':', err); + throw err; + }); + }; + + this.addUser = function (userId, roomId) { + typeCheck('userId', 'string', userId); + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'PUT', + path: '/rooms/' + roomId + '/users/add', + json: { + user_ids: [userId] + } + }).then(function () { + return _this.roomStore.addUserToRoom(roomId, userId); + }).catch(function (err) { + _this.logger.warn('error adding user ' + userId + ' to room ' + roomId + ':', err); + throw err; + }); + }; + + this.removeUser = function (userId, roomId) { + typeCheck('userId', 'string', userId); + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'PUT', + path: '/rooms/' + roomId + '/users/remove', + json: { + user_ids: [userId] + } + }).then(function () { + return _this.roomStore.removeUserFromRoom(roomId, userId); + }).catch(function (err) { + _this.logger.warn('error removing user ' + userId + ' from room ' + roomId + ':', err); + throw err; + }); + }; + + this.sendMessage = function () { + var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + text = _ref3.text, + roomId = _ref3.roomId; + + typeCheck('text', 'string', text); + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'POST', + path: '/rooms/' + roomId + '/messages', + json: { text: text } + }).then(pipe(JSON.parse, prop('message_id'))).catch(function (err) { + _this.logger.warn('error sending message to room ' + roomId + ':', err); + throw err; + }); + }; + + this.fetchMessages = function (roomId) { + var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + initialId = _ref4.initialId, + limit = _ref4.limit, + direction = _ref4.direction; + + typeCheck('roomId', 'number', roomId); + initialId && typeCheck('initialId', 'number', initialId); + limit && typeCheck('limit', 'number', limit); + direction && checkOneOf('direction', ['older', 'newer'], direction); + return _this.apiInstance.request({ + method: 'GET', + path: '/rooms/' + roomId + '/messages?' + urlEncode({ + initial_id: initialId, + limit: limit, + direction: direction + }) + }).then(function (res) { + var messages = map(compose(_this.decorateMessage, parseBasicMessage), JSON.parse(res)); + return _this.userStore.fetchMissingUsers(uniq(map(prop('senderId'), messages))).then(function () { + return sort(function (x, y) { + return x.id - y.id; + }, messages); + }); + }).catch(function (err) { + _this.logger.warn('error fetching messages from room ' + roomId + ':', err); + throw err; + }); + }; + + this.subscribeToRoom = function (roomId) { + var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var messageLimit = arguments[2]; + + typeCheck('roomId', 'number', roomId); + typeCheckObj('hooks', 'function', hooks); + messageLimit && typeCheck('messageLimit', 'number', messageLimit); + // TODO what is the desired behaviour if there is already a subscription to + // this room? Close the old one? Throw an error? Merge the hooks? + _this.roomSubscriptions[roomId] = new RoomSubscription({ + roomId: roomId, + hooks: hooks, + messageLimit: messageLimit, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + logger: _this.logger + }); + return _this.roomSubscriptions[roomId].connect(); + }; + + this.decorateMessage = function (basicMessage) { + return new Message(basicMessage, _this.userStore, _this.roomStore); + }; + + this.establishUserSubscription = function (hooks) { + _this.userSubscription = new UserSubscription({ + hooks: hooks, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + typingIndicators: _this.typingIndicators, + roomSubscriptions: _this.roomSubscriptions + }); + return _this.userSubscription.connect().then(function (_ref5) { + var user = _ref5.user, + basicRooms = _ref5.basicRooms; + + _this.avatarURL = user.avatarURL; + _this.createdAt = user.createdAt; + _this.customData = user.customData; + _this.name = user.name; + _this.updatedAt = user.updatedAt; + _this.roomStore.initialize(indexBy(prop('id'), basicRooms)); + }).then(_this.initializeUserStore); + }; + + this.establishPresenceSubscription = function (hooks) { + _this.presenceSubscription = new PresenceSubscription({ + hooks: hooks, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + presenceStore: _this.presenceStore, + roomSubscriptions: _this.roomSubscriptions + }); + return _this.presenceSubscription.connect(); + }; + + this.initializeUserStore = function () { + return _this.userStore.fetchMissingUsers(uniq(chain(prop('userIds'), _this.rooms))).catch(function (err) { + _this.logger.warn('error fetching initial user information:', err); + }).then(function () { + _this.userStore.initialize({}); + }); + }; + + this.id = id; + this.apiInstance = apiInstance; + this.logger = apiInstance.logger; + this.presenceStore = new Store(); + this.userStore = new UserStore({ + instance: this.apiInstance, + presenceStore: this.presenceStore, + logger: this.logger + }); + this.roomStore = new RoomStore({ + instance: this.apiInstance, + userStore: this.userStore, + logger: this.logger + }); + this.typingIndicators = new TypingIndicators({ + userId: this.id, + instance: this.apiInstance, + logger: this.logger + }); + this.roomSubscriptions = {}; + } + + /* public */ + + createClass(CurrentUser, [{ + key: 'rooms', + get: function get$$1() { + return values(this.roomStore.snapshot()); + } + }, { + key: 'users', + get: function get$$1() { + return values(this.userStore.snapshot()); + } + + // TODO attachments + + + /* internal */ + + }]); + return CurrentUser; +}(); + +var ChatManager = +// TODO accept a tokenProviderUrl and create a default tokenProvider? +function ChatManager() { + var _this = this; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var instanceLocator = _ref.instanceLocator, + tokenProvider = _ref.tokenProvider, + userId = _ref.userId, + options = objectWithoutProperties(_ref, ['instanceLocator', 'tokenProvider', 'userId']); + classCallCheck(this, ChatManager); + + this.connect = function () { + var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + typeCheckObj('hooks', 'function', hooks); + var currentUser = new CurrentUser({ + id: _this.userId, + apiInstance: _this.apiInstance + }); + return Promise.all([currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) + // currentUser.initializeCursorStore() + ]).then(function () { + return currentUser; + }); + }; + + typeCheck('instanceLocator', 'string', instanceLocator); + typeCheck('tokenProvider', 'object', tokenProvider); + typeCheck('tokenProvider.fetchToken', 'function', tokenProvider.fetchToken); + typeCheck('userId', 'string', userId); + var cluster = split(':', instanceLocator)[1]; + if (cluster === undefined) { + throw new TypeError('expected instanceLocator to be of the format x:y:z, but was ' + instanceLocator); + } + var baseClient = options.baseClient || new pusherPlatform_1({ + host: cluster + '.' + pusherPlatform_2, + logger: options.logger + }); + if (typeof tokenProvider.setUserId === 'function') { + tokenProvider.setUserId(userId); + } + var instanceOptions = { + client: baseClient, + locator: instanceLocator, + logger: options.logger, + tokenProvider: tokenProvider + }; + this.apiInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit', + serviceVersion: 'v1' + }, instanceOptions)); + this.filesInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit_files', + serviceVersion: 'v1' + }, instanceOptions)); + this.cursorsInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit_cursors', + serviceVersion: 'v1' + }, instanceOptions)); + this.userId = userId; +}; + +var main = { TokenProvider: TokenProvider, ChatManager: ChatManager }; + +return main; + +}))); diff --git a/dist/web/declarations/attachment.d.ts b/dist/web/declarations/attachment.d.ts new file mode 100644 index 0000000..1e89409 --- /dev/null +++ b/dist/web/declarations/attachment.d.ts @@ -0,0 +1,6 @@ +interface Attachment { + fetchRequired: boolean; + link: string; + type: string; +} +export default Attachment; diff --git a/dist/web/declarations/basic_cursor.d.ts b/dist/web/declarations/basic_cursor.d.ts new file mode 100644 index 0000000..1ab80b5 --- /dev/null +++ b/dist/web/declarations/basic_cursor.d.ts @@ -0,0 +1,8 @@ +interface BasicCursor { + cursorType: number; + position: number; + roomId: number; + updatedAt: string; + userId: string; +} +export default BasicCursor; diff --git a/dist/web/declarations/basic_message.d.ts b/dist/web/declarations/basic_message.d.ts new file mode 100644 index 0000000..b28e155 --- /dev/null +++ b/dist/web/declarations/basic_message.d.ts @@ -0,0 +1,11 @@ +import Attachment from './attachment'; +interface BasicMessage { + id: number; + senderId: string; + roomId: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; +} +export default BasicMessage; diff --git a/dist/web/declarations/basic_message_enricher.d.ts b/dist/web/declarations/basic_message_enricher.d.ts new file mode 100644 index 0000000..a8f7e15 --- /dev/null +++ b/dist/web/declarations/basic_message_enricher.d.ts @@ -0,0 +1,38 @@ +import { Logger } from 'pusher-platform'; +import BasicMessage from './basic_message'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import Room from './room'; +import User from './user'; +export interface MessageEnrichmentCompletionHandlers { + onSuccess: (message: Message) => void; + onError: (error: any) => void; +} +export declare type MessageIdsToCompletionHandlers = { + [key: number]: MessageEnrichmentCompletionHandlers; +}; +export declare type UserIdsToBasicMessageIds = { + [key: string]: number[]; +}; +export declare type MessageEnrichmentResult = Message | any; +export declare type MessageIdsToEnrichmentResults = { + [key: number]: MessageEnrichmentResult; +}; +export declare type MessageIdsToBasicMessages = { + [key: number]: BasicMessage; +}; +export default class BasicMessageEnricher { + userStore: GlobalUserStore; + room: Room; + logger: Logger; + private completionOrderList; + private messageIdToCompletionHandlers; + private enrichedMessagesAwaitingCompletionCalls; + private userIdsBeingRetrieved; + private userIdsToBasicMessageIds; + private messagesAwaitingEnrichmentDependentOnUserRetrieval; + constructor(userStore: GlobalUserStore, room: Room, logger: Logger); + enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; + enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; + callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; +} diff --git a/dist/web/declarations/basic_user.d.ts b/dist/web/declarations/basic_user.d.ts new file mode 100644 index 0000000..fb90490 --- /dev/null +++ b/dist/web/declarations/basic_user.d.ts @@ -0,0 +1,6 @@ +interface BasicUser { + id: string; + createdAt: string; + updatedAt: string; +} +export default BasicUser; diff --git a/dist/web/declarations/chat_manager.d.ts b/dist/web/declarations/chat_manager.d.ts new file mode 100644 index 0000000..49a8817 --- /dev/null +++ b/dist/web/declarations/chat_manager.d.ts @@ -0,0 +1,25 @@ +import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +export interface ChatManagerOptions { + instanceLocator: string; + tokenProvider: TokenProvider; + logger?: Logger; + baseClient?: BaseClient; + userId: string; +} +export default class ChatManager { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userId: string; + private userStore; + private userSubscription; + constructor(options: ChatManagerOptions); + connect(options: ConnectOptions): void; +} +export interface ConnectOptions { + delegate?: ChatManagerDelegate; + onSuccess: (currentUser: CurrentUser) => void; + onError: (error: any) => void; +} diff --git a/dist/web/declarations/chat_manager_delegate.d.ts b/dist/web/declarations/chat_manager_delegate.d.ts new file mode 100644 index 0000000..5b2d790 --- /dev/null +++ b/dist/web/declarations/chat_manager_delegate.d.ts @@ -0,0 +1,16 @@ +import Room from './room'; +import User from './user'; +interface ChatManagerDelegate { + addedToRoom?: (room: Room) => void; + removedFromRoom?: (room: Room) => void; + roomUpdated?: (room: Room) => void; + roomDeleted?: (room: Room) => void; + userStartedTyping?: (room: Room, user: User) => void; + userStoppedTyping?: (room: Room, user: User) => void; + userJoinedRoom?: (room: Room, user: User) => void; + userLeftRoom?: (room: Room, user: User) => void; + userCameOnline?: (user: User) => void; + userWentOffline?: (user: User) => void; + error?: (error: any) => void; +} +export default ChatManagerDelegate; diff --git a/dist/web/declarations/constants.d.ts b/dist/web/declarations/constants.d.ts new file mode 100644 index 0000000..d18fd38 --- /dev/null +++ b/dist/web/declarations/constants.d.ts @@ -0,0 +1,2 @@ +export declare const TYPING_REQ_TTL = 1500; +export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/web/declarations/current_user.d.ts b/dist/web/declarations/current_user.d.ts new file mode 100644 index 0000000..77a8eae --- /dev/null +++ b/dist/web/declarations/current_user.d.ts @@ -0,0 +1,111 @@ +import { Instance } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import PresenceSubscription from './presence_subscription'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +import RoomStore from './room_store'; +export interface CreateRoomOptions { + name: string; + private?: boolean; + addUserIds?: string[]; +} +export interface UpdateRoomOptions { + name?: string; + isPrivate?: boolean; +} +export interface FetchRoomMessagesOptions { + initialId?: string; + limit?: number; + direction?: string; +} +export interface CurrentUserOptions { + id: string; + createdAt: string; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + rooms?: Room[]; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; +} +export interface DataAttachment { + file: Blob; + name: string; +} +export interface LinkAttachment { + link: string; + type: string; +} +export declare type GenericAttachment = LinkAttachment | DataAttachment; +export interface AttachmentBody { + resource_link: string; + type: string; +} +export interface SendMessageOptions { + attachment?: GenericAttachment; + roomId: number; + text?: string; +} +export interface CompleteMessageOptions { + attachment?: AttachmentBody; + roomId: number; + text?: string; + user_id: string; +} +export default class CurrentUser { + id: string; + createdAt: string; + cursors: { + [roomId: string]: BasicCursor; + }; + cursorsReq: Promise; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + userStore: GlobalUserStore; + roomStore: RoomStore; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + pathFriendlyId: string; + presenceSubscription: PresenceSubscription; + typingRequestSent: { + [roomId: string]: number; + }; + readonly rooms: Room[]; + constructor(options: CurrentUserOptions); + updateWithPropertiesOf(currentUser: CurrentUser): void; + setupPresenceSubscription(delegate?: ChatManagerDelegate): void; + createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + populateRoomUserStore(room: Room): void; + addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; + deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; + joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; + sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; + subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; + fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; + fetchAttachment(attachmentURL: string): Promise; + private isDataAttachment(attachment); + private isLinkAttachment(attachment); + private uploadFile(file, fileName, roomId); + private sendMessageWithCompleteOptions(options, onSuccess, onError); + private subscribeToCursors(room, roomDelegate); + private getRooms(path, onSuccess, onError); +} diff --git a/dist/web/declarations/cursor.d.ts b/dist/web/declarations/cursor.d.ts new file mode 100644 index 0000000..3aa3524 --- /dev/null +++ b/dist/web/declarations/cursor.d.ts @@ -0,0 +1,10 @@ +import Room from './room'; +import User from './user'; +interface Cursor { + cursorType: number; + position: number; + room: Room; + updatedAt: string; + user: User; +} +export default Cursor; diff --git a/dist/web/declarations/cursor_subscription.d.ts b/dist/web/declarations/cursor_subscription.d.ts new file mode 100644 index 0000000..08e991b --- /dev/null +++ b/dist/web/declarations/cursor_subscription.d.ts @@ -0,0 +1,23 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import Cursor from './cursor'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +export interface CursorSubscriptionOptions { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; +} +export default class CursorSubscription { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; + constructor(options: CursorSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; +} diff --git a/dist/web/declarations/cursor_types.d.ts b/dist/web/declarations/cursor_types.d.ts new file mode 100644 index 0000000..01f22f7 --- /dev/null +++ b/dist/web/declarations/cursor_types.d.ts @@ -0,0 +1,4 @@ +declare enum CursorType { + Read = 0, +} +export default CursorType; diff --git a/dist/web/declarations/fetched_attachment.d.ts b/dist/web/declarations/fetched_attachment.d.ts new file mode 100644 index 0000000..907eddc --- /dev/null +++ b/dist/web/declarations/fetched_attachment.d.ts @@ -0,0 +1,11 @@ +export interface FetchedAttachmentFile { + bytes: number; + lastModified: number; + name: string; +} +interface FetchedAttachment { + file: FetchedAttachmentFile; + link: string; + ttl: number; +} +export default FetchedAttachment; diff --git a/dist/web/declarations/global_user_store.d.ts b/dist/web/declarations/global_user_store.d.ts new file mode 100644 index 0000000..7712fe4 --- /dev/null +++ b/dist/web/declarations/global_user_store.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import PresencePayload from './presence_payload'; +import User from './user'; +import UserStoreCore from './user_store_core'; +export interface GlobalUserStoreOptions { + apiInstance: Instance; + userStoreCore?: UserStoreCore; +} +export default class GlobalUserStore { + private apiInstance; + private userStoreCore; + constructor(options: GlobalUserStoreOptions); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; + handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; + fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; + initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; +} diff --git a/dist/web/declarations/index.d.ts b/dist/web/declarations/index.d.ts new file mode 100644 index 0000000..8118af7 --- /dev/null +++ b/dist/web/declarations/index.d.ts @@ -0,0 +1,10 @@ +import { BaseClient } from 'pusher-platform'; +import ChatManager from './chat_manager'; +import TokenProvider from './token_provider'; +export { BaseClient, ChatManager, TokenProvider }; +declare const _default: { + BaseClient: typeof BaseClient; + ChatManager: typeof ChatManager; + TokenProvider: typeof TokenProvider; +}; +export default _default; diff --git a/dist/web/declarations/message.d.ts b/dist/web/declarations/message.d.ts new file mode 100644 index 0000000..d7bd58d --- /dev/null +++ b/dist/web/declarations/message.d.ts @@ -0,0 +1,13 @@ +import Attachment from './attachment'; +import Room from './room'; +import User from './user'; +interface Message { + id: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; + sender: User; + room: Room; +} +export default Message; diff --git a/dist/web/declarations/payload_deserializer.d.ts b/dist/web/declarations/payload_deserializer.d.ts new file mode 100644 index 0000000..bb635f2 --- /dev/null +++ b/dist/web/declarations/payload_deserializer.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import Attachment from './attachment'; +import BasicCursor from './basic_cursor'; +import BasicMessage from './basic_message'; +import BasicUser from './basic_user'; +import CurrentUser from './current_user'; +import FetchedAttachment from './fetched_attachment'; +import GlobalUserStore from './global_user_store'; +import PresencePayload from './presence_payload'; +import Room from './room'; +import User from './user'; +export default class PayloadDeserializer { + static createUserFromPayload(userPayload: any): User; + static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; + static createRoomFromPayload(roomPayload: any): Room; + static createBasicMessageFromPayload(messagePayload: any): BasicMessage; + static createBasicCursorFromPayload(payload: any): BasicCursor; + static createPresencePayloadFromPayload(payload: any): PresencePayload; + static createBasicUserFromPayload(payload: any): BasicUser; + static createAttachmentFromPayload(payload: any): Attachment | undefined; + static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; +} diff --git a/dist/web/declarations/presence_payload.d.ts b/dist/web/declarations/presence_payload.d.ts new file mode 100644 index 0000000..c2a2215 --- /dev/null +++ b/dist/web/declarations/presence_payload.d.ts @@ -0,0 +1,7 @@ +import PresenceState from './presence_state'; +interface PresencePayload { + userId: string; + state: PresenceState; + lastSeenAt?: string; +} +export default PresencePayload; diff --git a/dist/web/declarations/presence_state.d.ts b/dist/web/declarations/presence_state.d.ts new file mode 100644 index 0000000..b7bd7d0 --- /dev/null +++ b/dist/web/declarations/presence_state.d.ts @@ -0,0 +1,4 @@ +export default class PresenceState { + stringValue: string; + constructor(state: string); +} diff --git a/dist/web/declarations/presence_subscription.d.ts b/dist/web/declarations/presence_subscription.d.ts new file mode 100644 index 0000000..53583cc --- /dev/null +++ b/dist/web/declarations/presence_subscription.d.ts @@ -0,0 +1,22 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import RoomStore from './room_store'; +export interface PresenceSubscriptionOptions { + apiInstance: Instance; + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; +} +export default class PresenceSubscription { + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; + private apiInstance; + constructor(options: PresenceSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + end(): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; +} diff --git a/dist/web/declarations/room.d.ts b/dist/web/declarations/room.d.ts new file mode 100644 index 0000000..f62e355 --- /dev/null +++ b/dist/web/declarations/room.d.ts @@ -0,0 +1,28 @@ +import CursorSubscription from './cursor_subscription'; +import RoomSubscription from './room_subscription'; +import RoomUserStore from './room_user_store'; +export interface RoomOptions { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds?: string[]; +} +export default class Room { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds: string[]; + userStore: RoomUserStore; + subscription?: RoomSubscription; + cursorSubscription?: CursorSubscription; + constructor(options: RoomOptions); + updateWithPropertiesOfRoom(room: Room): void; +} diff --git a/dist/web/declarations/room_delegate.d.ts b/dist/web/declarations/room_delegate.d.ts new file mode 100644 index 0000000..fbfb142 --- /dev/null +++ b/dist/web/declarations/room_delegate.d.ts @@ -0,0 +1,16 @@ +import Cursor from './cursor'; +import Message from './message'; +import User from './user'; +interface RoomDelegate { + newMessage?: (message: Message) => void; + userStartedTyping?: (user: User) => void; + userStoppedTyping?: (user: User) => void; + userJoined?: (user: User) => void; + userLeft?: (user: User) => void; + userCameOnlineInRoom?: (user: User) => void; + userWentOfflineInRoom?: (user: User) => void; + usersUpdated?: () => void; + error?: (error: any) => void; + cursorSet?: (cursor: Cursor) => void; +} +export default RoomDelegate; diff --git a/dist/web/declarations/room_store.d.ts b/dist/web/declarations/room_store.d.ts new file mode 100644 index 0000000..9d9befa --- /dev/null +++ b/dist/web/declarations/room_store.d.ts @@ -0,0 +1,16 @@ +import { Instance } from 'pusher-platform'; +import Room from './room'; +export interface RoomStoreOptions { + rooms: Room[]; + apiInstance: Instance; +} +export default class RoomStore { + rooms: Room[]; + apiInstance: Instance; + constructor(options: RoomStoreOptions); + room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + addOrMerge(room: Room): Room; + remove(id: number): Room | undefined; + findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; +} diff --git a/dist/web/declarations/room_subscription.d.ts b/dist/web/declarations/room_subscription.d.ts new file mode 100644 index 0000000..c37121a --- /dev/null +++ b/dist/web/declarations/room_subscription.d.ts @@ -0,0 +1,15 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicMessageEnricher from './basic_message_enricher'; +import RoomDelegate from './room_delegate'; +export interface RoomSubscriptionOptions { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; +} +export default class RoomSubscription { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; + constructor(options: RoomSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; +} diff --git a/dist/web/declarations/room_user_store.d.ts b/dist/web/declarations/room_user_store.d.ts new file mode 100644 index 0000000..eb1f60f --- /dev/null +++ b/dist/web/declarations/room_user_store.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +import UserStoreCore from './user_store_core'; +export default class RoomUserStore { + private userStoreCore; + constructor(userStoreCore?: UserStoreCore); + addOrMerge(user: User): User; + remove(id: string): User | undefined; +} diff --git a/dist/web/declarations/token_provider.d.ts b/dist/web/declarations/token_provider.d.ts new file mode 100644 index 0000000..5fb85e9 --- /dev/null +++ b/dist/web/declarations/token_provider.d.ts @@ -0,0 +1,29 @@ +import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; +export interface TokenProviderAuthContextOptions { + queryParams?: TokenProviderAuthContextQueryParams; + headers?: TokenProviderAuthContextHeaders; +} +export declare type TokenProviderAuthContextHeaders = { + [key: string]: string; +}; +export declare type TokenProviderAuthContextQueryParams = { + [key: string]: string; +}; +export interface TokenProviderOptions { + authContext?: TokenProviderAuthContextOptions; + url: string; +} +export default class TokenProvider implements PlatformTokenProvider { + authContext?: TokenProviderAuthContextOptions; + url: string; + userId?: string; + cachedAccessToken?: string; + cachedTokenExpiresAt?: number; + constructor(options: TokenProviderOptions); + readonly cacheIsStale: boolean; + fetchToken(tokenParams?: any): Promise; + clearToken(token?: string): void; + makeAuthRequest(): Promise; + private cache(accessToken, expiresIn); + private unixTimeNow(); +} diff --git a/dist/web/declarations/user.d.ts b/dist/web/declarations/user.d.ts new file mode 100644 index 0000000..7e0b5f4 --- /dev/null +++ b/dist/web/declarations/user.d.ts @@ -0,0 +1,23 @@ +import PresencePayload from './presence_payload'; +import PresenceState from './presence_state'; +export interface UserOptions { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; +} +export default class User { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; + presenceState: PresenceState; + lastSeenAt?: string; + constructor(options: UserOptions); + updateWithPropertiesOfUser(user: User): this; + updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; +} diff --git a/dist/web/declarations/user_store_core.d.ts b/dist/web/declarations/user_store_core.d.ts new file mode 100644 index 0000000..a55ef61 --- /dev/null +++ b/dist/web/declarations/user_store_core.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +export default class UserStoreCore { + private users; + constructor(users?: User[]); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + find(id: string): User | undefined; +} diff --git a/dist/web/declarations/user_subscription.d.ts b/dist/web/declarations/user_subscription.d.ts new file mode 100644 index 0000000..42ea461 --- /dev/null +++ b/dist/web/declarations/user_subscription.d.ts @@ -0,0 +1,38 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +export interface UserSubscriptionOptions { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; +} +export default class UserSubscription { + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; + currentUser?: CurrentUser; + private apiInstance; + private filesInstance; + private cursorsInstance; + private typingTimers; + constructor(options: UserSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; + reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; + parseAddedToRoomPayload(eventName: string, data: any): void; + parseRemovedFromRoomPayload(eventName: string, data: any): void; + parseRoomUpdatedPayload(eventName: string, data: any): void; + parseRoomDeletedPayload(eventName: string, data: any): void; + parseUserJoinedPayload(eventName: string, data: any): void; + parseUserLeftPayload(eventName: string, data: any): void; + parseIsTypingPayload(eventName: string, data: any, userId: string): void; + private startedTyping(roomId, userId); + private stoppedTyping(roomId, userId); +} diff --git a/dist/web/declarations/utils.d.ts b/dist/web/declarations/utils.d.ts new file mode 100644 index 0000000..dbf28ce --- /dev/null +++ b/dist/web/declarations/utils.d.ts @@ -0,0 +1,5 @@ +export declare function urlEncode(data: any): string; +export declare function queryString(data: any): string; +export declare function queryParamsFromFullUrl(url: string): any; +export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; +export declare function allPromisesSettled(promises: Array>): Promise; diff --git a/dist/worker/chatkit.worker.js b/dist/worker/chatkit.worker.js new file mode 100644 index 0000000..8efc579 --- /dev/null +++ b/dist/worker/chatkit.worker.js @@ -0,0 +1,3982 @@ +var Chatkit = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 7); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var current_user_1 = __webpack_require__(11); +var presence_state_1 = __webpack_require__(4); +var room_1 = __webpack_require__(18); +var user_1 = __webpack_require__(20); +var utils_1 = __webpack_require__(1); +var checkPresenceAndTypeOfFieldsInPayload = function (requiredFieldsWithTypes, payload) { + Object.keys(requiredFieldsWithTypes).forEach(function (key) { + if (payload[key] === undefined) { + throw new Error("Payload missing key: " + key); + } + var receivedType = typeof payload[key]; + var expectedType = requiredFieldsWithTypes[key]; + if (receivedType !== expectedType) { + throw new Error("Value for key: " + key + " in payload was " + receivedType + ", expected " + expectedType); + } + }); +}; +var PayloadDeserializer = (function () { + function PayloadDeserializer() { + } + PayloadDeserializer.createUserFromPayload = function (userPayload) { + var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); + return new user_1.default({ + avatarURL: userPayload.avatar_url, + createdAt: basicUser.createdAt, + customData: userPayload.custom_data, + id: basicUser.id, + name: userPayload.name, + updatedAt: basicUser.updatedAt, + }); + }; + PayloadDeserializer.createCurrentUserFromPayload = function (userPayload, apiInstance, filesInstance, cursorsInstance, userStore) { + var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); + return new current_user_1.default({ + apiInstance: apiInstance, + avatarURL: userPayload.avatar_url, + createdAt: basicUser.createdAt, + cursorsInstance: cursorsInstance, + customData: userPayload.custom_data, + filesInstance: filesInstance, + id: basicUser.id, + name: userPayload.name, + updatedAt: basicUser.updatedAt, + userStore: userStore, + }); + }; + PayloadDeserializer.createRoomFromPayload = function (roomPayload) { + var requiredFieldsWithTypes = { + created_at: 'string', + created_by_id: 'string', + id: 'number', + name: 'string', + private: 'boolean', + updated_at: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, roomPayload); + var memberUserIds = []; + if (roomPayload.member_user_ids) { + memberUserIds = roomPayload.member_user_ids; + } + return new room_1.default({ + createdAt: roomPayload.created_at, + createdByUserId: roomPayload.created_by_id, + deletedAt: roomPayload.deleted_at, + id: roomPayload.id, + isPrivate: roomPayload.private, + name: roomPayload.name, + updatedAt: roomPayload.updated_at, + userIds: memberUserIds, + }); + }; + PayloadDeserializer.createBasicMessageFromPayload = function (messagePayload) { + var requiredFieldsWithTypes = { + created_at: 'string', + id: 'number', + room_id: 'number', + text: 'string', + updated_at: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, messagePayload); + var attachment = this.createAttachmentFromPayload(messagePayload.attachment); + return { + attachment: attachment, + createdAt: messagePayload.created_at, + id: messagePayload.id, + roomId: messagePayload.room_id, + senderId: messagePayload.user_id, + text: messagePayload.text, + updatedAt: messagePayload.updated_at, + }; + }; + PayloadDeserializer.createBasicCursorFromPayload = function (payload) { + var requiredFieldsWithTypes = { + cursor_type: 'number', + position: 'number', + room_id: 'number', + updated_at: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + return { + cursorType: payload.cursor_type, + position: payload.position, + roomId: payload.room_id, + updatedAt: payload.updated_at, + userId: payload.user_id, + }; + }; + PayloadDeserializer.createPresencePayloadFromPayload = function (payload) { + var requiredFieldsWithTypes = { + state: 'string', + user_id: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var state = new presence_state_1.default(payload.state); + return { + lastSeenAt: payload.last_seen_at, + state: state, + userId: payload.user_id, + }; + }; + PayloadDeserializer.createBasicUserFromPayload = function (payload) { + var requiredFieldsWithTypes = { + created_at: 'string', + id: 'string', + updated_at: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + return { + createdAt: payload.created_at, + id: payload.id, + updatedAt: payload.updated_at, + }; + }; + PayloadDeserializer.createAttachmentFromPayload = function (payload) { + if (payload === undefined) { + return undefined; + } + var requiredFieldsWithTypes = { + resource_link: 'string', + type: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var linkQueryParams = utils_1.queryParamsFromFullUrl(payload.resource_link); + var fetchRequired = linkQueryParams.chatkit_link !== undefined && + linkQueryParams.chatkit_link === 'true'; + return { + fetchRequired: fetchRequired, + link: payload.resource_link, + type: payload.type, + }; + }; + PayloadDeserializer.createFetchedAttachmentFromPayload = function (payload) { + if (payload === undefined) { + return undefined; + } + var requiredFieldsWithTypes = { + file: 'object', + resource_link: 'string', + ttl: 'number', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); + var requiredFieldsWithTypesForFileField = { + bytes: 'number', + last_modified: 'number', + name: 'string', + }; + checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypesForFileField, payload.file); + var file = payload.file; + var bytes = file.bytes, name = file.name; + return { + file: { + bytes: bytes, + lastModified: file.last_modified, + name: name, + }, + link: payload.resource_link, + ttl: payload.ttl, + }; + }; + return PayloadDeserializer; +}()); +exports.default = PayloadDeserializer; + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function urlEncode(data) { + return Object.keys(data) + .filter(function (key) { return data[key] !== undefined; }) + .map(function (key) { return key + "=" + encodeURIComponent(data[key]); }) + .join('&'); +} +exports.urlEncode = urlEncode; +function queryString(data) { + var encodedData = urlEncode(data); + return encodedData ? "?" + encodedData : ''; +} +exports.queryString = queryString; +function queryParamsFromFullUrl(url) { + if (url.indexOf('?') === -1) { + return {}; + } + var splitUrl = url.split('?'); + var queryStr = splitUrl.slice(1).join('&'); + return queryParamObject(queryStr); +} +exports.queryParamsFromFullUrl = queryParamsFromFullUrl; +function querylessUrlAndQueryObjectFromFullUrl(urlString) { + if (urlString.indexOf('?') === -1) { + return { + queryObject: {}, + querylessUrl: urlString, + }; + } + var splitUrl = urlString.split('?'); + var querylessUrl = splitUrl[0]; + var queryStr = splitUrl.slice(1).join('&'); + return { + queryObject: queryParamObject(queryStr), + querylessUrl: querylessUrl, + }; +} +function queryParamObject(queryParamString) { + return queryParamString + .split('&') + .map(function (str) { + var _a = str.split('='), key = _a[0], value = _a[1]; + return _b = {}, _b[key] = decodeURI(value), _b; + var _b; + }) + .reduce(function (prev, curr) { return Object.assign(prev, curr); }); +} +function mergeQueryParamsIntoUrl(urlString, queryParams) { + var _a = querylessUrlAndQueryObjectFromFullUrl(urlString), querylessUrl = _a.querylessUrl, queryObject = _a.queryObject; + var fullQueryString = queryString(Object.assign(queryObject, queryParams)); + return "" + querylessUrl + fullQueryString; +} +exports.mergeQueryParamsIntoUrl = mergeQueryParamsIntoUrl; +function allPromisesSettled(promises) { + return Promise.all(promises.map(function (p) { + return Promise.resolve(p).then(function (v) { return ({ + state: 'fulfilled', + value: v, + }); }, function (r) { return ({ + reason: r, + state: 'rejected', + }); }); + })); +} +exports.allPromisesSettled = allPromisesSettled; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(8); + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TYPING_REQ_TTL = 1500; +exports.TYPING_REQ_LEEWAY = 500; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var PresenceState = (function () { + function PresenceState(state) { + switch (state) { + case 'online': + this.stringValue = state; + break; + case 'offline': + this.stringValue = state; + break; + default: + this.stringValue = 'unknown'; + break; + } + } + return PresenceState; +}()); +exports.default = PresenceState; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var UserStoreCore = (function () { + function UserStoreCore(users) { + if (users === void 0) { users = new Array(); } + this.users = users; + } + UserStoreCore.prototype.addOrMerge = function (user) { + var existingUser = this.users.find(function (el) { return el.id === user.id; }); + if (existingUser) { + existingUser.updateWithPropertiesOfUser(user); + return existingUser; + } + else { + this.users.push(user); + return user; + } + }; + UserStoreCore.prototype.remove = function (id) { + var indexOfUser = this.users.findIndex(function (el) { return el.id === id; }); + if (indexOfUser === -1) { + return undefined; + } + var user = this.users[indexOfUser]; + this.users.splice(indexOfUser, 1); + return user; + }; + UserStoreCore.prototype.find = function (id) { + return this.users.find(function (el) { return el.id === id; }); + }; + return UserStoreCore; +}()); +exports.default = UserStoreCore; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var utils_1 = __webpack_require__(1); +var TokenProvider = (function () { + function TokenProvider(options) { + this.authContext = options.authContext || {}; + this.url = options.url; + } + Object.defineProperty(TokenProvider.prototype, "cacheIsStale", { + get: function () { + if (this.cachedAccessToken && this.cachedTokenExpiresAt) { + return this.unixTimeNow() > this.cachedTokenExpiresAt; + } + return true; + }, + enumerable: true, + configurable: true + }); + TokenProvider.prototype.fetchToken = function (tokenParams) { + var _this = this; + if (this.cacheIsStale) { + return this.makeAuthRequest().then(function (responseBody) { + var access_token = responseBody.access_token, expires_in = responseBody.expires_in; + _this.cache(access_token, expires_in); + return access_token; + }); + } + return new Promise(function (resolve, reject) { + resolve(_this.cachedAccessToken); + }); + }; + TokenProvider.prototype.clearToken = function (token) { + this.cachedAccessToken = undefined; + this.cachedTokenExpiresAt = undefined; + }; + TokenProvider.prototype.makeAuthRequest = function () { + var url; + var authRequestQueryParams = (this.authContext || {}).queryParams || {}; + if (this.userId === undefined) { + url = utils_1.mergeQueryParamsIntoUrl(this.url, authRequestQueryParams); + } + else { + var authContextWithUserId = __assign({ user_id: this.userId }, authRequestQueryParams); + url = utils_1.mergeQueryParamsIntoUrl(this.url, authContextWithUserId); + } + var authRequestHeaders = (this.authContext || {}).headers || {}; + var headers = __assign((_a = {}, _a['Content-Type'] = 'application/x-www-form-urlencoded', _a), authRequestHeaders); + var body = utils_1.urlEncode({ grant_type: 'client_credentials' }); + return pusher_platform_1.sendRawRequest({ + body: body, + headers: headers, + method: 'POST', + url: url, + }).then(function (res) { + return JSON.parse(res); + }); + var _a; + }; + TokenProvider.prototype.cache = function (accessToken, expiresIn) { + this.cachedAccessToken = accessToken; + this.cachedTokenExpiresAt = this.unixTimeNow() + expiresIn; + }; + TokenProvider.prototype.unixTimeNow = function () { + return Math.floor(Date.now() / 1000); + }; + return TokenProvider; +}()); +exports.default = TokenProvider; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +exports.BaseClient = pusher_platform_1.BaseClient; +var chat_manager_1 = __webpack_require__(9); +exports.ChatManager = chat_manager_1.default; +var token_provider_1 = __webpack_require__(6); +exports.TokenProvider = token_provider_1.default; +exports.default = { + BaseClient: pusher_platform_1.BaseClient, + ChatManager: chat_manager_1.default, + TokenProvider: token_provider_1.default, +}; + + +/***/ }), +/* 8 */ +/***/ (function(module, exports) { + +var PusherPlatform = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 10); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function responseToHeadersObject(headerStr) { + var headers = {}; + if (!headerStr) { + return headers; + } + var headerPairs = headerStr.split('\u000d\u000a'); + for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { + var headerPair = headerPairs_1[_i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) { + var key = headerPair.substring(0, index); + var val = headerPair.substring(index + 2); + headers[key] = val; + } + } + return headers; +} +exports.responseToHeadersObject = responseToHeadersObject; +var ErrorResponse = (function () { + function ErrorResponse(statusCode, headers, info) { + this.statusCode = statusCode; + this.headers = headers; + this.info = info; + } + ErrorResponse.fromXHR = function (xhr) { + var errorInfo = xhr.responseText; + try { + errorInfo = JSON.parse(xhr.responseText); + } + catch (e) { + } + return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); + }; + return ErrorResponse; +}()); +exports.ErrorResponse = ErrorResponse; +var NetworkError = (function () { + function NetworkError(error) { + this.error = error; + } + return NetworkError; +}()); +exports.NetworkError = NetworkError; +var XhrReadyState; +(function (XhrReadyState) { + XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; + XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; + XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; + XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; + XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; +})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; + LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; + LogLevel[LogLevel["INFO"] = 3] = "INFO"; + LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; + LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; +})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); +var ConsoleLogger = (function () { + function ConsoleLogger(threshold) { + if (threshold === void 0) { threshold = 2; } + this.threshold = threshold; + var groups = Array(); + var hr = '--------------------------------------------------------------------------------'; + if (!self.console.group) { + self.console.group = function (label) { + groups.push(label); + self.console.log('%c \nBEGIN GROUP: %c', hr, label); + }; + } + if (!self.console.groupEnd) { + self.console.groupEnd = function () { + self.console.log('END GROUP: %c\n%c', groups.pop(), hr); + }; + } + } + ConsoleLogger.prototype.verbose = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(self.console.log, LogLevel.VERBOSE, items); + }; + ConsoleLogger.prototype.debug = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(self.console.log, LogLevel.DEBUG, items); + }; + ConsoleLogger.prototype.info = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(self.console.info, LogLevel.INFO, items); + }; + ConsoleLogger.prototype.warn = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(self.console.warn, LogLevel.WARNING, items); + }; + ConsoleLogger.prototype.error = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(self.console.error, LogLevel.ERROR, items); + }; + ConsoleLogger.prototype.log = function (logFunction, level, items) { + var _this = this; + if (level >= this.threshold) { + var loggerSignature_1 = "Logger." + LogLevel[level]; + if (items.length > 1) { + self.console.group(); + items.forEach(function (item) { + _this.errorAwareLog(logFunction, item, loggerSignature_1); + }); + self.console.groupEnd(); + } + else { + this.errorAwareLog(logFunction, items[0], loggerSignature_1); + } + } + }; + ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { + if (item.info && item.info.error_uri) { + var errorDesc = item.info.error_description; + var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; + logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); + } + else { + logFunction(loggerSignature + ": ", item); + } + }; + return ConsoleLogger; +}()); +exports.ConsoleLogger = ConsoleLogger; +var EmptyLogger = (function () { + function EmptyLogger() { + } + EmptyLogger.prototype.verbose = function (message, error) { }; + EmptyLogger.prototype.debug = function (message, error) { }; + EmptyLogger.prototype.info = function (message, error) { }; + EmptyLogger.prototype.warn = function (message, error) { }; + EmptyLogger.prototype.error = function (message, error) { }; + return EmptyLogger; +}()); +exports.EmptyLogger = EmptyLogger; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createRetryStrategyOptionsOrDefault = function (options) { + var initialTimeoutMillis = options.initialTimeoutMillis || 1000; + var maxTimeoutMillis = options.maxTimeoutMillis || 5000; + var limit = -1; + if (options.limit !== undefined && options.limit != null) { + limit = options.limit; + } + var increaseTimeout; + if (options.increaseTimeout !== undefined) { + increaseTimeout = options.increaseTimeout; + } + else { + increaseTimeout = function (currentTimeout) { + if (currentTimeout * 2 > maxTimeoutMillis) { + return maxTimeoutMillis; + } + else { + return currentTimeout * 2; + } + }; + } + return { + increaseTimeout: increaseTimeout, + initialTimeoutMillis: initialTimeoutMillis, + limit: limit, + maxTimeoutMillis: maxTimeoutMillis, + }; +}; +var Retry = (function () { + function Retry(waitTimeMillis) { + this.waitTimeMillis = waitTimeMillis; + } + return Retry; +}()); +exports.Retry = Retry; +var DoNotRetry = (function () { + function DoNotRetry(error) { + this.error = error; + } + return DoNotRetry; +}()); +exports.DoNotRetry = DoNotRetry; +var requestMethodIsSafe = function (method) { + method = method.toUpperCase(); + return (method === 'GET' || + method === 'HEAD' || + method === 'OPTIONS' || + method === 'SUBSCRIBE'); +}; +var RetryResolution = (function () { + function RetryResolution(options, logger, retryUnsafeRequests) { + this.options = options; + this.logger = logger; + this.retryUnsafeRequests = retryUnsafeRequests; + this.currentRetryCount = 0; + this.initialTimeoutMillis = options.initialTimeoutMillis; + this.maxTimeoutMillis = options.maxTimeoutMillis; + this.limit = options.limit; + this.increaseTimeoutFunction = options.increaseTimeout; + this.currentBackoffMillis = this.initialTimeoutMillis; + } + RetryResolution.prototype.attemptRetry = function (error) { + this.logger.verbose(this.constructor.name + ": Error received", error); + if (this.currentRetryCount >= this.limit && this.limit >= 0) { + this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); + return new DoNotRetry(error); + } + if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { + this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); + return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); + } + if (error instanceof network_1.NetworkError || + (error instanceof network_1.ErrorResponse && + requestMethodIsSafe(error.headers['Request-Method'])) || + this.retryUnsafeRequests) { + return this.shouldSafeRetry(error); + } + if (error instanceof network_1.NetworkError) { + return this.shouldSafeRetry(error); + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.shouldSafeRetry = function (error) { + if (error instanceof network_1.NetworkError) { + this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); + return new Retry(this.calulateMillisToRetry()); + } + else if (error instanceof network_1.ErrorResponse) { + if (error.statusCode >= 500 && error.statusCode < 600) { + this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); + return new Retry(this.calulateMillisToRetry()); + } + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.calulateMillisToRetry = function () { + this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); + this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); + return this.currentBackoffMillis; + }; + return RetryResolution; +}()); +exports.RetryResolution = RetryResolution; + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var logger_1 = __webpack_require__(1); +var request_1 = __webpack_require__(4); +var resuming_subscription_1 = __webpack_require__(5); +var retrying_subscription_1 = __webpack_require__(6); +var subscribe_strategy_1 = __webpack_require__(11); +var subscription_1 = __webpack_require__(12); +var token_providing_subscription_1 = __webpack_require__(7); +var http_1 = __webpack_require__(13); +var websocket_1 = __webpack_require__(14); +var transports_1 = __webpack_require__(8); +var BaseClient = (function () { + function BaseClient(options) { + this.options = options; + this.host = options.host.replace(/(\/)+$/, ''); + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.websocketTransport = new websocket_1.default(this.host); + this.httpTransport = new http_1.default(this.host, options.encrypted); + } + BaseClient.prototype.request = function (options, tokenParams) { + var _this = this; + if (options.tokenProvider) { + return options.tokenProvider + .fetchToken(tokenParams) + .then(function (token) { + if (options.headers !== undefined) { + options.headers['Authorization'] = "Bearer " + token; + } + else { + options.headers = (_a = {}, + _a['Authorization'] = "Bearer " + token, + _a); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + var _a; + }) + .catch(function (error) { + _this.logger.error(error); + }); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + }; + BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + return BaseClient; +}()); +exports.BaseClient = BaseClient; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +function executeNetworkRequest(createXhr, options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); + sendBody(xhr, options); + }); +} +exports.executeNetworkRequest = executeNetworkRequest; +function sendBody(xhr, options) { + if (options.json) { + xhr.send(JSON.stringify(options.json)); + } + else { + xhr.send(options.body); + } +} +function sendRawRequest(options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(new self.XMLHttpRequest(), resolve, reject); + xhr.open(options.method.toUpperCase(), options.url, true); + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + xhr.send(options.body); + }); +} +exports.sendRawRequest = sendRawRequest; +function attachOnReadyStateChangeHandler(xhr, resolve, reject) { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.response); + } + else if (xhr.status !== 0) { + reject(network_1.ErrorResponse.fromXHR(xhr)); + } + else { + reject(new network_1.NetworkError('No Connection')); + } + } + }; + return xhr; +} + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { + var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); + var ResumingSubscription = (function () { + function ResumingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + this.onTransition = onTransition; + var lastEventId = initialEventId; + logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); + if (lastEventId) { + headers['Last-Event-Id'] = lastEventId; + logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); + } + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpeningSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpenSubscriptionState; + }()); + var ResumingSubscriptionState = (function () { + function ResumingSubscriptionState(error, onTransition, lastEventId) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); + var executeSubscriptionOnce = function (error, lastEventId) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = self.setTimeout(function () { + executeNextSubscribeStrategy(lastEventId); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function (lastEventId) { + logger.verbose("ResumingSubscription: trying to re-establish the subscription"); + if (lastEventId) { + logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); + headers['Last-Event-Id'] = lastEventId; + } + _this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + executeSubscriptionOnce(error, lastEventId); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error, lastEventId); + } + ResumingSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + self.clearTimeout(this.timeout); + this.underlyingSubscription.unsubscribe(); + }; + return ResumingSubscriptionState; + }()); + var EndingSubscriptionState = (function () { + function EndingSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); + } + EndingSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription is already ending'); + }; + return EndingSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return ResumingSubscription; + }()); + return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { + var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); + var RetryingSubscription = (function () { + function RetryingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { + return onTransition(new RetryingSubscriptionState(error, onTransition)); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + throw new Error('Method not implemented.'); + }; + return OpeningSubscriptionState; + }()); + var RetryingSubscriptionState = (function () { + function RetryingSubscriptionState(error, onTransition) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); + var executeSubscriptionOnce = function (error) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = self.setTimeout(function () { + executeNextSubscribeStrategy(); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function () { + logger.verbose("RetryingSubscription: trying to re-establish the subscription"); + var underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { return executeSubscriptionOnce(error); }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error); + } + RetryingSubscriptionState.prototype.unsubscribe = function () { + self.clearTimeout(this.timeout); + this.onTransition(new EndedSubscriptionState()); + }; + return RetryingSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + this.onTransition(new EndedSubscriptionState()); + }; + return OpenSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return RetryingSubscription; + }()); + return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { + if (tokenProvider) { + return function (listeners, headers) { + return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); + }; + } + return nextSubscribeStrategy; +}; +var TokenProvidingSubscription = (function () { + function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { + var _this = this; + this.logger = logger; + this.listeners = listeners; + this.headers = headers; + this.tokenProvider = tokenProvider; + this.nextSubscribeStrategy = nextSubscribeStrategy; + this.unsubscribe = function () { + _this.state.unsubscribe(); + _this.state = new InactiveState(_this.logger); + }; + this.state = new ActiveState(logger, headers, nextSubscribeStrategy); + this.subscribe(); + } + TokenProvidingSubscription.prototype.subscribe = function () { + var _this = this; + this.tokenProvider + .fetchToken() + .then(function (token) { + var existingListeners = Object.assign({}, _this.listeners); + _this.state.subscribe(token, { + onEnd: function (error) { + _this.state = new InactiveState(_this.logger); + existingListeners.onEnd(error); + }, + onError: function (error) { + if (_this.isTokenExpiredError(error)) { + _this.tokenProvider.clearToken(token); + _this.subscribe(); + } + else { + _this.state = new InactiveState(_this.logger); + existingListeners.onError(error); + } + }, + onEvent: _this.listeners.onEvent, + onOpen: _this.listeners.onOpen, + }); + }) + .catch(function (error) { + _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); + _this.state = new InactiveState(_this.logger); + _this.listeners.onError(error); + }); + }; + TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { + return (error instanceof network_1.ErrorResponse && + error.statusCode === 401 && + error.info === 'authentication/expired'); + }; + return TokenProvidingSubscription; +}()); +var ActiveState = (function () { + function ActiveState(logger, headers, nextSubscribeStrategy) { + this.logger = logger; + this.headers = headers; + this.nextSubscribeStrategy = nextSubscribeStrategy; + logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); + } + ActiveState.prototype.subscribe = function (token, listeners) { + var _this = this; + this.putTokenIntoHeader(token); + this.underlyingSubscription = this.nextSubscribeStrategy({ + onEnd: function (error) { + _this.logger.verbose("TokenProvidingSubscription: subscription ended"); + listeners.onEnd(error); + }, + onError: function (error) { + _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); + listeners.onError(error); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + _this.logger.verbose("TokenProvidingSubscription: subscription opened"); + listeners.onOpen(headers); + }, + onRetrying: listeners.onRetrying, + }, this.headers); + }; + ActiveState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + }; + ActiveState.prototype.putTokenIntoHeader = function (token) { + this.headers['Authorization'] = "Bearer " + token; + this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); + }; + return ActiveState; +}()); +var InactiveState = (function () { + function InactiveState(logger) { + this.logger = logger; + logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); + } + InactiveState.prototype.subscribe = function (token, listeners) { + this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); + }; + InactiveState.prototype.unsubscribe = function () { + this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); + }; + return InactiveState; +}()); + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createTransportStrategy = function (path, transport, logger) { + return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; +}; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HOST_BASE = 'pusherplatform.io'; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +exports.BaseClient = base_client_1.BaseClient; +var host_base_1 = __webpack_require__(9); +exports.HOST_BASE = host_base_1.HOST_BASE; +var instance_1 = __webpack_require__(15); +exports.Instance = instance_1.default; +var logger_1 = __webpack_require__(1); +exports.ConsoleLogger = logger_1.ConsoleLogger; +exports.EmptyLogger = logger_1.EmptyLogger; +var network_1 = __webpack_require__(0); +exports.ErrorResponse = network_1.ErrorResponse; +exports.NetworkError = network_1.NetworkError; +exports.responseToHeadersObject = network_1.responseToHeadersObject; +exports.XhrReadyState = network_1.XhrReadyState; +var request_1 = __webpack_require__(4); +exports.executeNetworkRequest = request_1.executeNetworkRequest; +exports.sendRawRequest = request_1.sendRawRequest; +var resuming_subscription_1 = __webpack_require__(5); +exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; +exports.DoNotRetry = retry_strategy_1.DoNotRetry; +exports.Retry = retry_strategy_1.Retry; +exports.RetryResolution = retry_strategy_1.RetryResolution; +var retrying_subscription_1 = __webpack_require__(6); +exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; +var token_providing_subscription_1 = __webpack_require__(7); +exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; +var transports_1 = __webpack_require__(8); +exports.createTransportStrategy = transports_1.createTransportStrategy; +exports.default = { + BaseClient: base_client_1.BaseClient, + ConsoleLogger: logger_1.ConsoleLogger, + EmptyLogger: logger_1.EmptyLogger, + Instance: instance_1.default, +}; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { + return { + onEnd: subListeners.onEnd, + onError: subListeners.onError, + onEvent: subListeners.onEvent, + onOpen: subListeners.onOpen, + onRetrying: subListeners.onRetrying, + }; +}; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.replaceMissingListenersWithNoOps = function (listeners) { + var onEndNoOp = function (error) { }; + var onEnd = listeners.onEnd || onEndNoOp; + var onErrorNoOp = function (error) { }; + var onError = listeners.onError || onErrorNoOp; + var onEventNoOp = function (event) { }; + var onEvent = listeners.onEvent || onEventNoOp; + var onOpenNoOp = function (headers) { }; + var onOpen = listeners.onOpen || onOpenNoOp; + var onRetryingNoOp = function () { }; + var onRetrying = listeners.onRetrying || onRetryingNoOp; + var onSubscribeNoOp = function () { }; + var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; + return { + onEnd: onEnd, + onError: onError, + onEvent: onEvent, + onOpen: onOpen, + onRetrying: onRetrying, + onSubscribe: onSubscribe, + }; +}; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var HttpTransportState; +(function (HttpTransportState) { + HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; + HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; + HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; + HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; + HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; +})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); +var HttpSubscription = (function () { + function HttpSubscription(xhr, listeners) { + var _this = this; + this.gotEOS = false; + this.lastNewlineIndex = 0; + this.state = HttpTransportState.UNOPENED; + this.xhr = xhr; + this.listeners = listeners; + this.xhr.onreadystatechange = function () { + switch (_this.xhr.readyState) { + case network_1.XhrReadyState.UNSENT: + case network_1.XhrReadyState.OPENED: + case network_1.XhrReadyState.HEADERS_RECEIVED: + _this.assertStateIsIn(HttpTransportState.OPENING); + break; + case network_1.XhrReadyState.LOADING: + _this.onLoading(); + break; + case network_1.XhrReadyState.DONE: + _this.onDone(); + break; + } + }; + this.state = HttpTransportState.OPENING; + this.xhr.send(); + return this; + } + HttpSubscription.prototype.unsubscribe = function () { + this.state = HttpTransportState.ENDED; + this.xhr.abort(); + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + }; + HttpSubscription.prototype.onLoading = function () { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + self.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN); + var err = this.onChunk(); + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + if (err) { + this.state = HttpTransportState.ENDED; + if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else { + } + } + }; + HttpSubscription.prototype.onDone = function () { + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + var err = this.onChunk(); + if (err) { + this.state = HttpTransportState.ENDED; + if (err.statusCode === 204) { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else if (this.state <= HttpTransportState.ENDING) { + if (this.listeners.onError) { + this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); + } + } + else { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + } + else { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); + if (this.state === HttpTransportState.ENDED) { + return; + } + else if (this.xhr.status === 0) { + if (this.listeners.onError) { + this.listeners.onError(new network_1.NetworkError('Connection lost.')); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); + } + } + } + }; + HttpSubscription.prototype.onChunk = function () { + this.assertStateIsIn(HttpTransportState.OPEN); + var response = this.xhr.responseText; + var newlineIndex = response.lastIndexOf('\n'); + if (newlineIndex > this.lastNewlineIndex) { + var rawEvents = response + .slice(this.lastNewlineIndex, newlineIndex) + .split('\n'); + this.lastNewlineIndex = newlineIndex; + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + if (rawEvent.length === 0) { + continue; + } + var data = JSON.parse(rawEvent); + var err = this.onMessage(data); + if (err != null) { + return err; + } + } + } + }; + HttpSubscription.prototype.assertStateIsIn = function () { + var _this = this; + var validStates = []; + for (var _i = 0; _i < arguments.length; _i++) { + validStates[_i] = arguments[_i]; + } + var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); + if (!stateIsValid) { + var expectedStates = validStates + .map(function (state) { return HttpTransportState[state]; }) + .join(', '); + var actualState = HttpTransportState[this.state]; + self.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); + } + }; + HttpSubscription.prototype.onMessage = function (message) { + this.assertStateIsIn(HttpTransportState.OPEN); + this.verifyMessage(message); + switch (message[0]) { + case 0: + return null; + case 1: + return this.onEventMessage(message); + case 255: + return this.onEOSMessage(message); + default: + return new Error('Unknown Message: ' + JSON.stringify(message)); + } + }; + HttpSubscription.prototype.onEventMessage = function (eventMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eventMessage.length !== 4) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; + if (typeof id !== 'string') { + return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); + } + if (this.listeners.onEvent) { + this.listeners.onEvent({ body: body, headers: headers, eventId: id }); + } + return null; + }; + HttpSubscription.prototype.onEOSMessage = function (eosMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eosMessage.length !== 4) { + return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); + } + var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; + if (typeof statusCode !== 'number') { + return new Error('Invalid EOS Status Code'); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid EOS ElementsHeaders'); + } + this.state = HttpTransportState.ENDING; + return new network_1.ErrorResponse(statusCode, headers, info); + }; + HttpSubscription.prototype.verifyMessage = function (message) { + if (this.gotEOS) { + return new Error('Got another message after EOS message'); + } + if (!Array.isArray(message)) { + return new Error('Message is not an array'); + } + if (message.length < 1) { + return new Error('Message is empty array'); + } + }; + return HttpSubscription; +}()); +var HttpTransport = (function () { + function HttpTransport(host, encrypted) { + if (encrypted === void 0) { encrypted = true; } + this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; + } + HttpTransport.prototype.request = function (requestOptions) { + return this.createXHR(this.baseURL, requestOptions); + }; + HttpTransport.prototype.subscribe = function (path, listeners, headers) { + var requestOptions = { + headers: headers, + method: 'SUBSCRIBE', + path: path, + }; + return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); + }; + HttpTransport.prototype.createXHR = function (baseURL, options) { + var xhr = new self.XMLHttpRequest(); + var path = options.path.replace(/^\/+/, ''); + var endpoint = baseURL + "/" + path; + xhr.open(options.method.toUpperCase(), endpoint, true); + xhr = this.setJSONHeaderIfAppropriate(xhr, options); + if (options.jwt) { + xhr.setRequestHeader('authorization', "Bearer " + options.jwt); + } + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + return xhr; + }; + HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { + if (options.json) { + xhr.setRequestHeader('content-type', 'application/json'); + } + return xhr; + }; + return HttpTransport; +}()); +exports.default = HttpTransport; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var SubscribeMessageType = 100; +var OpenMessageType = 101; +var EventMessageType = 102; +var UnsubscribeMessageType = 198; +var EosMessageType = 199; +var PingMessageType = 16; +var PongMessageType = 17; +var CloseMessageType = 99; +var WSReadyState; +(function (WSReadyState) { + WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; + WSReadyState[WSReadyState["Open"] = 1] = "Open"; + WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; + WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; +})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); +var WsSubscriptions = (function () { + function WsSubscriptions() { + this.subscriptions = {}; + } + WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { + this.subscriptions[subID] = { + headers: headers, + listeners: listeners, + path: path, + }; + return subID; + }; + WsSubscriptions.prototype.has = function (subID) { + return this.subscriptions[subID] !== undefined; + }; + WsSubscriptions.prototype.isEmpty = function () { + return Object.keys(this.subscriptions).length === 0; + }; + WsSubscriptions.prototype.remove = function (subID) { + return delete this.subscriptions[subID]; + }; + WsSubscriptions.prototype.get = function (subID) { + return this.subscriptions[subID]; + }; + WsSubscriptions.prototype.getAll = function () { + return this.subscriptions; + }; + WsSubscriptions.prototype.getAllAsArray = function () { + var _this = this; + return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); + }; + WsSubscriptions.prototype.removeAll = function () { + this.subscriptions = {}; + }; + return WsSubscriptions; +}()); +var WsSubscription = (function () { + function WsSubscription(wsTransport, subID) { + this.wsTransport = wsTransport; + this.subID = subID; + } + WsSubscription.prototype.unsubscribe = function () { + this.wsTransport.unsubscribe(this.subID); + }; + return WsSubscription; +}()); +var pingIntervalMs = 30000; +var pingTimeoutMs = 10000; +var WebSocketTransport = (function () { + function WebSocketTransport(host) { + this.webSocketPath = '/ws'; + this.forcedClose = false; + this.closedError = null; + this.baseURL = "wss://" + host + this.webSocketPath; + this.lastSubscriptionID = 0; + this.subscriptions = new WsSubscriptions(); + this.pendingSubscriptions = new WsSubscriptions(); + this.connect(); + } + WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { + this.tryReconnectIfNeeded(); + var subID = this.lastSubscriptionID++; + if (this.socket.readyState !== WSReadyState.Open) { + this.pendingSubscriptions.add(subID, path, listeners, headers); + return new WsSubscription(this, subID); + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + return new WsSubscription(this, subID); + }; + WebSocketTransport.prototype.unsubscribe = function (subID) { + this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); + var subscription = this.subscriptions.get(subID); + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + this.subscriptions.remove(subID); + }; + WebSocketTransport.prototype.connect = function () { + var _this = this; + this.close(); + this.forcedClose = false; + this.closedError = null; + this.socket = new self.WebSocket(this.baseURL); + this.socket.onopen = function (event) { + var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); + allPendingSubscriptions.forEach(function (subscription) { + var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; + _this.subscribePending(path, listeners, headers, subID); + }); + _this.pendingSubscriptions.removeAll(); + _this.pingInterval = self.setInterval(function () { + if (_this.pongTimeout) { + return; + } + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + return; + } + _this.sendMessage(_this.getMessage(PingMessageType, now)); + _this.lastSentPingID = now; + _this.pongTimeout = self.setTimeout(function () { + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + _this.pongTimeout = null; + return; + } + _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); + }, pingTimeoutMs); + }, pingIntervalMs); + }; + this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; + this.socket.onerror = function (event) { + _this.close(new network_1.NetworkError('Connection was lost.')); + }; + this.socket.onclose = function (event) { + if (!_this.forcedClose) { + _this.tryReconnectIfNeeded(); + return; + } + var callback = _this.closedError + ? function (subscription) { + if (subscription.listeners.onError) { + subscription.listeners.onError(_this.closedError); + } + } + : function (subscription) { + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + }; + var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false + ? _this.pendingSubscriptions + : _this.subscriptions; + allSubscriptions.getAllAsArray().forEach(callback); + allSubscriptions.removeAll(); + if (_this.closedError) { + _this.tryReconnectIfNeeded(); + } + }; + }; + WebSocketTransport.prototype.close = function (error) { + if (!(this.socket instanceof self.WebSocket)) { + return; + } + this.forcedClose = true; + this.closedError = error; + this.socket.close(); + self.clearTimeout(this.pingInterval); + self.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.tryReconnectIfNeeded = function () { + if (this.socket.readyState !== WSReadyState.Closed) { + return; + } + this.connect(); + }; + WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { + if (subID === undefined) { + self.console.logger.debug("Subscription to path " + path + " has an undefined ID"); + return; + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + }; + WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { + return [messageType, id, path, headers]; + }; + WebSocketTransport.prototype.sendMessage = function (message) { + if (this.socket.readyState !== WSReadyState.Open) { + return self.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); + } + this.socket.send(JSON.stringify(message)); + }; + WebSocketTransport.prototype.subscription = function (subID) { + return this.subscriptions.get(subID); + }; + WebSocketTransport.prototype.receiveMessage = function (event) { + this.lastMessageReceivedTimestamp = new Date().getTime(); + var message; + try { + message = JSON.parse(event.data); + } + catch (err) { + this.close(new Error("Message is not valid JSON format. Getting " + event.data)); + return; + } + var nonValidMessageError = this.validateMessage(message); + if (nonValidMessageError) { + this.close(new Error(nonValidMessageError.message)); + return; + } + var messageType = message.shift(); + switch (messageType) { + case PongMessageType: + this.onPongMessage(message); + return; + case PingMessageType: + this.onPingMessage(message); + return; + case CloseMessageType: + this.onCloseMessage(message); + return; + } + var subID = message.shift(); + var subscription = this.subscription(subID); + if (!subscription) { + this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); + return; + } + var listeners = subscription.listeners; + switch (messageType) { + case OpenMessageType: + this.onOpenMessage(message, subID, listeners); + break; + case EventMessageType: + this.onEventMessage(message, listeners); + break; + case EosMessageType: + this.onEOSMessage(message, subID, listeners); + break; + default: + this.close(new Error('Received non existing type of message.')); + } + }; + WebSocketTransport.prototype.validateMessage = function (message) { + if (!Array.isArray(message)) { + return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); + } + if (message.length < 1) { + return new Error("Message is empty array: " + JSON.stringify(message)); + } + return null; + }; + WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { + if (subscriptionListeners.onOpen) { + subscriptionListeners.onOpen(message[1]); + } + }; + WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { + if (eventMessage.length !== 3) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; + if (typeof eventId !== 'string') { + return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); + } + if (subscriptionListeners.onEvent) { + subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); + } + }; + WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { + this.subscriptions.remove(subID); + if (eosMessage.length !== 3) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); + } + return; + } + var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; + if (typeof statusCode !== 'number') { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS Status Code')); + } + return; + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); + } + return; + } + if (statusCode === 204) { + if (subscriptionListeners.onEnd) { + subscriptionListeners.onEnd(null); + } + return; + } + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); + } + return; + }; + WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { + var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; + if (typeof statusCode !== 'number') { + return this.close(new Error('Close message: Invalid EOS Status Code')); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); + } + this.close(); + }; + WebSocketTransport.prototype.onPongMessage = function (message) { + var receviedPongID = message[0]; + if (this.lastSentPingID !== receviedPongID) { + this.close(new network_1.NetworkError("Didn't received pong with proper ID")); + } + self.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.onPingMessage = function (message) { + var receviedPingID = message[0]; + this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); + }; + return WebSocketTransport; +}()); +exports.default = WebSocketTransport; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +var host_base_1 = __webpack_require__(9); +var logger_1 = __webpack_require__(1); +var Instance = (function () { + function Instance(options) { + if (!options.locator) { + throw new Error('Expected `locator` property in Instance options!'); + } + var splitInstanceLocator = options.locator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instance locator property is in the wrong format!'); + } + if (!options.serviceName) { + throw new Error('Expected `serviceName` property in Instance options!'); + } + if (!options.serviceVersion) { + throw new Error('Expected `serviceVersion` property in Instance otpions!'); + } + this.platformVersion = splitInstanceLocator[0]; + this.cluster = splitInstanceLocator[1]; + this.id = splitInstanceLocator[2]; + this.serviceName = options.serviceName; + this.serviceVersion = options.serviceVersion; + this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.client = + options.client || + new base_client_1.BaseClient({ + encrypted: options.encrypted, + host: this.host, + logger: this.logger, + }); + this.tokenProvider = options.tokenProvider; + } + Instance.prototype.request = function (options, tokenParams) { + options.path = this.absPath(options.path); + if (options.headers == null || options.headers === undefined) { + options.headers = {}; + } + options.tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.request(options, tokenParams); + }; + Instance.prototype.subscribeNonResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); + }; + Instance.prototype.subscribeResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); + }; + Instance.prototype.absPath = function (relativePath) { + return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) + .replace(/\/+/g, '/') + .replace(/\/+$/, ''); + }; + return Instance; +}()); +exports.default = Instance; + + +/***/ }) +/******/ ]); + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var global_user_store_1 = __webpack_require__(10); +var payload_deserializer_1 = __webpack_require__(0); +var token_provider_1 = __webpack_require__(6); +var user_subscription_1 = __webpack_require__(21); +var ChatManager = (function () { + function ChatManager(options) { + if (typeof options.userId !== 'string') { + throw new Error('Please provide a userId to the ChatManger constructor!'); + } + this.userId = options.userId; + var splitInstanceLocator = options.instanceLocator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instanceLocator property is in the wrong format!'); + } + var cluster = splitInstanceLocator[1]; + var baseClient = options.baseClient || + new pusher_platform_1.BaseClient({ + host: cluster + "." + pusher_platform_1.HOST_BASE, + logger: options.logger, + }); + if (options.tokenProvider instanceof token_provider_1.default) { + options.tokenProvider.userId = this.userId; + } + var sharedInstanceOptions = { + client: baseClient, + locator: options.instanceLocator, + logger: options.logger, + tokenProvider: options.tokenProvider, + }; + this.apiInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.filesInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_files', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.cursorsInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_cursors', serviceVersion: 'v1' }, sharedInstanceOptions)); + this.userStore = new global_user_store_1.default({ apiInstance: this.apiInstance }); + } + ChatManager.prototype.connect = function (options) { + var _this = this; + var cursorsReq = this.cursorsInstance + .request({ + method: 'GET', + path: "/cursors/0/users/" + this.userId, + }) + .then(function (res) { + var cursors = JSON.parse(res); + var cursorsByRoom = {}; + cursors.forEach(function (c) { + cursorsByRoom[c.room_id] = payload_deserializer_1.default.createBasicCursorFromPayload(c); + }); + return cursorsByRoom; + }) + .catch(function (err) { + _this.cursorsInstance.logger.verbose('Error getting cursors:', err); + return {}; + }); + this.userSubscription = new user_subscription_1.default({ + apiInstance: this.apiInstance, + connectCompletionHandler: function (currentUser, error) { + if (currentUser) { + currentUser.cursorsReq = cursorsReq + .then(function (cursors) { + currentUser.cursors = cursors; + }); + options.onSuccess(currentUser); + } + else { + options.onError(error); + } + }, + cursorsInstance: this.cursorsInstance, + delegate: options.delegate, + filesInstance: this.filesInstance, + userStore: this.userStore, + }); + this.apiInstance.subscribeNonResuming({ + listeners: { + onError: options.onError, + onEvent: this.userSubscription.handleEvent.bind(this.userSubscription), + }, + path: '/users', + }); + }; + return ChatManager; +}()); +exports.default = ChatManager; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var user_store_core_1 = __webpack_require__(5); +var utils_1 = __webpack_require__(1); +var GlobalUserStore = (function () { + function GlobalUserStore(options) { + this.apiInstance = options.apiInstance; + this.userStoreCore = options.userStoreCore || new user_store_core_1.default(); + } + GlobalUserStore.prototype.addOrMerge = function (user) { + return this.userStoreCore.addOrMerge(user); + }; + GlobalUserStore.prototype.remove = function (id) { + return this.userStoreCore.remove(id); + }; + GlobalUserStore.prototype.user = function (id, onSuccess, onError) { + this.findOrGetUser(id, onSuccess, onError); + }; + GlobalUserStore.prototype.findOrGetUser = function (id, onSuccess, onError) { + var user = this.userStoreCore.find(id); + if (user) { + onSuccess(user); + return; + } + this.getUser(id, onSuccess, onError); + }; + GlobalUserStore.prototype.getUser = function (id, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: "/users/" + id, + }) + .then(function (res) { + var userPayload = JSON.parse(res); + var user = payload_deserializer_1.default.createUserFromPayload(userPayload); + var userToReturn = _this.addOrMerge(user); + onSuccess(userToReturn); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + onError(error); + }); + }; + GlobalUserStore.prototype.handleInitialPresencePayloadsAfterRoomJoin = function (payloads, onComplete) { + this.handleInitialPresencePayloads(payloads, onComplete); + }; + GlobalUserStore.prototype.handleInitialPresencePayloads = function (payloads, onComplete) { + var _this = this; + var presencePayloadPromises = new Array(); + payloads.forEach(function (payload) { + var presencePromise = new Promise(function (resolve, reject) { + _this.user(payload.userId, function (user) { + user.updatePresenceInfoIfAppropriate(payload); + resolve(); + }, function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + reject(); + }); + }); + presencePayloadPromises.push(presencePromise); + }); + utils_1.allPromisesSettled(presencePayloadPromises).then(function () { + onComplete(); + }); + }; + GlobalUserStore.prototype.fetchUsersWithIds = function (userIds, onSuccess, onError) { + var _this = this; + if (userIds.length === 0) { + this.apiInstance.logger.verbose('Requested to fetch users for a list of user ids which was empty'); + onSuccess([]); + return; + } + var userIdsString = userIds.join(','); + var qs = utils_1.queryString({ user_ids: userIdsString }); + this.apiInstance + .request({ + method: 'GET', + path: "/users_by_ids" + qs, + }) + .then(function (res) { + var usersPayload = JSON.parse(res); + var users = usersPayload.map(function (userPayload) { + var user = payload_deserializer_1.default.createUserFromPayload(userPayload); + var addedOrUpdatedUser = _this.userStoreCore.addOrMerge(user); + return addedOrUpdatedUser; + }); + onSuccess(users); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error fetching user information:', error); + onError(error); + }); + }; + GlobalUserStore.prototype.initialFetchOfUsersWithIds = function (userIds, onSuccess, onError) { + this.fetchUsersWithIds(userIds, onSuccess, onError); + }; + return GlobalUserStore; +}()); +exports.default = GlobalUserStore; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var pusher_platform_1 = __webpack_require__(2); +var basic_message_enricher_1 = __webpack_require__(12); +var cursor_subscription_1 = __webpack_require__(13); +var cursor_types_1 = __webpack_require__(14); +var payload_deserializer_1 = __webpack_require__(0); +var presence_subscription_1 = __webpack_require__(15); +var room_store_1 = __webpack_require__(16); +var room_subscription_1 = __webpack_require__(17); +var constants_1 = __webpack_require__(3); +var utils_1 = __webpack_require__(1); +var CurrentUser = (function () { + function CurrentUser(options) { + var rooms = options.rooms, id = options.id, apiInstance = options.apiInstance, filesInstance = options.filesInstance, cursorsInstance = options.cursorsInstance; + var validRooms = rooms || []; + this.id = id; + this.createdAt = options.createdAt; + this.cursors = {}; + this.updatedAt = options.updatedAt; + this.name = options.name; + this.avatarURL = options.avatarURL; + this.customData = options.customData; + this.roomStore = new room_store_1.default({ apiInstance: apiInstance, rooms: validRooms }); + this.apiInstance = apiInstance; + this.filesInstance = filesInstance; + this.cursorsInstance = cursorsInstance; + this.userStore = options.userStore; + this.pathFriendlyId = encodeURIComponent(id); + this.typingRequestSent = {}; + } + Object.defineProperty(CurrentUser.prototype, "rooms", { + get: function () { + return this.roomStore.rooms; + }, + enumerable: true, + configurable: true + }); + CurrentUser.prototype.updateWithPropertiesOf = function (currentUser) { + this.updatedAt = currentUser.updatedAt; + this.name = currentUser.name; + this.customData = currentUser.customData; + }; + CurrentUser.prototype.setupPresenceSubscription = function (delegate) { + this.presenceSubscription = new presence_subscription_1.default({ + apiInstance: this.apiInstance, + delegate: delegate, + roomStore: this.roomStore, + userStore: this.userStore, + }); + this.apiInstance.subscribeNonResuming({ + listeners: { + onError: delegate && delegate.error, + onEvent: this.presenceSubscription.handleEvent.bind(this.presenceSubscription), + }, + path: "/users/" + this.id + "/presence", + }); + }; + CurrentUser.prototype.createRoom = function (options, onSuccess, onError) { + var _this = this; + var roomData = { + created_by_id: this.id, + name: options.name, + private: options.private || false, + }; + if (options.addUserIds && options.addUserIds.length > 0) { + roomData['user_ids'] = options.addUserIds; + } + this.apiInstance + .request({ + json: roomData, + method: 'POST', + path: '/rooms', + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var addedOrMergedRoom = _this.roomStore.addOrMerge(room); + _this.populateRoomUserStore(addedOrMergedRoom); + onSuccess(addedOrMergedRoom); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error creating room:', error); + onError(error); + }); + }; + CurrentUser.prototype.populateRoomUserStore = function (room) { + var _this = this; + var userPromises = new Array(); + room.userIds.forEach(function (userId) { + var userPromise = new Promise(function (resolve, reject) { + _this.userStore.user(userId, function (user) { + room.userStore.addOrMerge(user); + resolve(); + }, function (error) { + _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room (room.name): " + error); + reject(); + }); + }); + userPromises.push(userPromise); + }); + utils_1.allPromisesSettled(userPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }; + CurrentUser.prototype.addUser = function (id, roomId, onSuccess, onError) { + this.addOrRemoveUsers(roomId, [id], 'add', onSuccess, onError); + }; + CurrentUser.prototype.removeUser = function (id, roomId, onSuccess, onError) { + this.addOrRemoveUsers(roomId, [id], 'remove', onSuccess, onError); + }; + CurrentUser.prototype.updateRoom = function (roomId, options, onSuccess, onError) { + var _this = this; + if (options.name === undefined && options.isPrivate === undefined) { + onSuccess(); + return; + } + var roomPayload = {}; + if (options.name) { + roomPayload['name'] = options.name; + } + if (options.isPrivate) { + roomPayload['private'] = options.isPrivate; + } + this.apiInstance + .request({ + json: roomPayload, + method: 'PUT', + path: "/rooms/" + roomId, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error updating room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.deleteRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'DELETE', + path: "/rooms/" + roomId, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error deleting room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.addOrRemoveUsers = function (roomId, userIds, membershipChange, onSuccess, onError) { + var _this = this; + var usersPayload = { + user_ids: userIds, + }; + this.apiInstance + .request({ + json: usersPayload, + method: 'PUT', + path: "/rooms/" + roomId + "/users/" + membershipChange, + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error when attempting to " + membershipChange + " users from room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.joinRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'POST', + path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/join", + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var addedOrMergedRoom = _this.roomStore.addOrMerge(room); + _this.populateRoomUserStore(addedOrMergedRoom); + onSuccess(addedOrMergedRoom); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error joining room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.leaveRoom = function (roomId, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'POST', + path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/leave", + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error leaving room " + roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.getJoinedRooms = function (onSuccess, onError) { + this.getUserRooms(false, onSuccess, onError); + }; + CurrentUser.prototype.getJoinableRooms = function (onSuccess, onError) { + this.getUserRooms(true, onSuccess, onError); + }; + CurrentUser.prototype.getUserRooms = function (onlyJoinable, onSuccess, onError) { + var joinableQueryItemValue = onlyJoinable ? 'true' : 'false'; + this.getRooms("/users/" + this.pathFriendlyId + "/rooms?joinable=" + joinableQueryItemValue, onSuccess, onError); + }; + CurrentUser.prototype.getAllRooms = function (onSuccess, onError) { + this.getRooms('/rooms', onSuccess, onError); + }; + CurrentUser.prototype.isTypingIn = function (roomId, onSuccess, onError) { + var _this = this; + var now = Date.now(); + var sent = this.typingRequestSent[roomId]; + var eventName = 'typing_start'; + var eventPayload = { + name: 'typing_start', + user_id: this.id, + }; + if (!sent || now - sent > constants_1.TYPING_REQ_TTL - constants_1.TYPING_REQ_LEEWAY) { + this.typingRequestSent[roomId] = now; + this.apiInstance + .request({ + json: eventPayload, + method: 'POST', + path: "/rooms/" + roomId + "/events", + }) + .then(function (res) { + onSuccess(); + }) + .catch(function (error) { + delete _this.typingRequestSent[roomId]; + _this.apiInstance.logger.verbose("Error sending " + eventName + " event in room " + roomId + ":", error); + onError(error); + }); + } + else { + onSuccess(); + } + }; + CurrentUser.prototype.setCursor = function (position, room, onSuccess, onError) { + var _this = this; + if (typeof position !== 'number') { + throw new Error('Cursor position should be a valid number'); + } + this.cursorsInstance + .request({ + json: { position: position }, + method: 'PUT', + path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id + "/users/" + this.id, + }) + .then(onSuccess) + .catch(function (err) { + _this.cursorsInstance.logger.verbose("Error setting cursor in room " + room.name + ":", err); + onError(err); + }); + }; + CurrentUser.prototype.sendMessage = function (options, onSuccess, onError) { + var _this = this; + var attachment = options.attachment, rest = __rest(options, ["attachment"]); + var completeOptions = __assign({ user_id: this.id }, rest); + if (attachment !== undefined) { + if (this.isDataAttachment(attachment)) { + var file = attachment.file, name = attachment.name; + this.uploadFile(file, name, options.roomId) + .then(function (fileRes) { + _this.sendMessageWithCompleteOptions(__assign({ attachment: fileRes, user_id: _this.id }, rest), onSuccess, onError); + }) + .catch(function (error) { + onError(error); + return; + }); + } + else if (this.isLinkAttachment(attachment)) { + var link = attachment.link, type = attachment.type; + completeOptions.attachment = { + resource_link: link, + type: type, + }; + this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); + } + else { + this.apiInstance.logger.debug('Message not sent: invalid attachment property provided: ', attachment); + } + } + else { + this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); + } + }; + CurrentUser.prototype.subscribeToRoom = function (room, roomDelegate, messageLimit) { + var _this = this; + var path = "/rooms/" + room.id; + if (messageLimit !== undefined) { + if (typeof messageLimit !== 'number') { + throw new Error('Message limit should be a valid number'); + } + path = path + "?message_limit=" + messageLimit; + } + this.cursorsReq.then(function () { + room.subscription = new room_subscription_1.default({ + basicMessageEnricher: new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger), + delegate: roomDelegate, + logger: _this.apiInstance.logger, + }); + _this.apiInstance.subscribeNonResuming({ + listeners: { + onError: roomDelegate.error, + onEvent: room.subscription.handleEvent.bind(room.subscription), + }, + path: path, + }); + _this.subscribeToCursors(room, roomDelegate); + }); + }; + CurrentUser.prototype.fetchMessagesFromRoom = function (room, fetchOptions, onSuccess, onError) { + var _this = this; + var initialIdQueryParam = fetchOptions.initialId + ? "initial_id=" + fetchOptions.initialId + : ''; + var limitQueryParam = fetchOptions.limit + ? "limit=" + fetchOptions.limit + : ''; + var directionQueryParam = fetchOptions.direction + ? "direction=" + fetchOptions.direction + : 'direction=older'; + var combinedQueryParams = [ + initialIdQueryParam, + limitQueryParam, + directionQueryParam, + ].join('&'); + this.apiInstance + .request({ + method: 'GET', + path: "/rooms/" + room.id + "/messages?" + combinedQueryParams, + }) + .then(function (res) { + var messagesPayload = JSON.parse(res); + var messages = new Array(); + var basicMessages = new Array(); + var messageUserIds = messagesPayload.map(function (messagePayload) { + var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(messagePayload); + basicMessages.push(basicMessage); + return basicMessage.id; + }); + var messageUserIdsSet = new Set(messageUserIds); + var userIdsToFetch = Array.from(messageUserIdsSet.values()); + _this.userStore.fetchUsersWithIds(userIdsToFetch, function (users) { + var messageEnricher = new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger); + var enrichmentPromises = new Array(); + basicMessages.forEach(function (basicMessage) { + var enrichmentPromise = new Promise(function (resolve, reject) { + messageEnricher.enrich(basicMessage, function (message) { + messages.push(message); + resolve(); + }, function (error) { + _this.apiInstance.logger.verbose("Unable to enrich basic mesage " + basicMessage.id + ": " + error); + reject(); + }); + }); + enrichmentPromises.push(enrichmentPromise); + }); + utils_1.allPromisesSettled(enrichmentPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + onSuccess(messages.sort(function (msgOne, msgTwo) { return msgOne.id - msgTwo.id; })); + }); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching users with ids " + userIdsToFetch + ":", error); + }); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error fetching messages froom room " + room.name + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.fetchAttachment = function (attachmentURL) { + if (!this.apiInstance.tokenProvider) { + return new Promise(function (resolve, reject) { + reject(new Error('Token provider not set on apiInstance')); + }); + } + return this.apiInstance.tokenProvider.fetchToken().then(function (token) { + return pusher_platform_1.sendRawRequest({ + headers: { + Authorization: "Bearer " + token, + }, + method: 'GET', + url: attachmentURL, + }).then(function (res) { + var attachmentPayload = JSON.parse(res); + var fetchedAttachment = payload_deserializer_1.default.createFetchedAttachmentFromPayload(attachmentPayload); + return fetchedAttachment; + }); + }); + }; + CurrentUser.prototype.isDataAttachment = function (attachment) { + return (attachment.file !== undefined && + attachment.name !== undefined); + }; + CurrentUser.prototype.isLinkAttachment = function (attachment) { + return (attachment.link !== undefined && + attachment.type !== undefined); + }; + CurrentUser.prototype.uploadFile = function (file, fileName, roomId) { + var data = new FormData(); + data.append('file', file, fileName); + return this.filesInstance + .request({ + body: data, + method: 'POST', + path: "/rooms/" + roomId + "/files/" + fileName, + }) + .then(function (res) { + return JSON.parse(res); + }); + }; + CurrentUser.prototype.sendMessageWithCompleteOptions = function (options, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + json: options, + method: 'POST', + path: "/rooms/" + options.roomId + "/messages", + }) + .then(function (res) { + var messageIdPayload = JSON.parse(res); + var messageId = messageIdPayload.message_id; + onSuccess(messageId); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose("Error sending message to room " + options.roomId + ":", error); + onError(error); + }); + }; + CurrentUser.prototype.subscribeToCursors = function (room, roomDelegate) { + var _this = this; + room.cursorSubscription = new cursor_subscription_1.default({ + delegate: roomDelegate, + handleCursorSetInternal: function (cursor) { + if (cursor.userId === _this.id && _this.cursors !== undefined) { + _this.cursors[cursor.roomId] = cursor; + } + }, + logger: this.cursorsInstance.logger, + room: room, + userStore: this.userStore, + }); + this.cursorsInstance.subscribeNonResuming({ + listeners: { + onEvent: room.cursorSubscription.handleEvent.bind(room.cursorSubscription), + }, + path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id, + }); + }; + CurrentUser.prototype.getRooms = function (path, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: path, + }) + .then(function (res) { + var roomsPayload = JSON.parse(res); + var rooms = roomsPayload.map(function (roomPayload) { + return payload_deserializer_1.default.createRoomFromPayload(roomPayload); + }); + onSuccess(rooms); + }) + .catch(function (error) { + _this.apiInstance.logger.verbose('Error when getting instance rooms:', error); + onError(error); + }); + }; + return CurrentUser; +}()); +exports.default = CurrentUser; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var BasicMessageEnricher = (function () { + function BasicMessageEnricher(userStore, room, logger) { + this.completionOrderList = []; + this.messageIdToCompletionHandlers = {}; + this.enrichedMessagesAwaitingCompletionCalls = {}; + this.userIdsBeingRetrieved = []; + this.userIdsToBasicMessageIds = {}; + this.messagesAwaitingEnrichmentDependentOnUserRetrieval = {}; + this.userStore = userStore; + this.room = room; + this.logger = logger; + } + BasicMessageEnricher.prototype.enrich = function (basicMessage, onSuccess, onError) { + var _this = this; + var basicMessageId = basicMessage.id; + var basicMessageSenderId = basicMessage.senderId; + this.completionOrderList.push(basicMessageId); + this.messageIdToCompletionHandlers[basicMessageId] = { + onError: onError, + onSuccess: onSuccess, + }; + if (this.userIdsToBasicMessageIds[basicMessageSenderId] === undefined) { + this.userIdsToBasicMessageIds[basicMessageSenderId] = [basicMessageId]; + } + else { + this.userIdsToBasicMessageIds[basicMessageSenderId].push(basicMessageId); + } + this.messagesAwaitingEnrichmentDependentOnUserRetrieval[basicMessageId] = basicMessage; + if (this.userIdsBeingRetrieved.indexOf(basicMessageSenderId) > -1) { + return; + } + else { + this.userIdsBeingRetrieved.push(basicMessageSenderId); + } + this.userStore.user(basicMessageSenderId, function (user) { + var basicMessageIds = _this.userIdsToBasicMessageIds[basicMessageSenderId]; + if (basicMessageIds === undefined) { + _this.logger.verbose("Fetched user information for user with id " + user.id + " but no messages needed information for this user"); + return; + } + var basicMessages = basicMessageIds + .map(function (bmId) { + return _this.messagesAwaitingEnrichmentDependentOnUserRetrieval[bmId]; + }) + .filter(function (el) { return el !== undefined; }); + _this.enrichMessagesWithUser(user, basicMessages); + var indexToRemove = _this.userIdsBeingRetrieved.indexOf(basicMessageSenderId); + if (indexToRemove > -1) { + _this.userIdsBeingRetrieved.splice(indexToRemove, 1); + } + }, function (error) { + _this.logger.debug("Unable to find user with id " + basicMessage.senderId + ", associated with message " + basicMessageId + ". Error:", error); + _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessageId, error); + }); + }; + BasicMessageEnricher.prototype.enrichMessagesWithUser = function (user, messages) { + var _this = this; + messages.forEach(function (basicMessage) { + var message = { + attachment: basicMessage.attachment, + createdAt: basicMessage.createdAt, + id: basicMessage.id, + room: _this.room, + sender: user, + text: basicMessage.text, + updatedAt: basicMessage.updatedAt, + }; + _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessage.id, message); + }); + }; + BasicMessageEnricher.prototype.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo = function (id, result) { + var nextIdToComplete = this.completionOrderList[0]; + if (nextIdToComplete === undefined) { + return; + } + this.enrichedMessagesAwaitingCompletionCalls[id] = result; + if (id !== nextIdToComplete) { + this.logger.verbose("Waiting to call completion handler for message id " + id + " as there are other older messages still to be enriched"); + return; + } + do { + var messageId = this.completionOrderList[0]; + var completionHandler = this.messageIdToCompletionHandlers[messageId]; + if (completionHandler === undefined) { + this.logger.verbose("Completion handler not stored for message id " + messageId); + return; + } + var res = this.enrichedMessagesAwaitingCompletionCalls[messageId]; + if (res === undefined) { + this.logger.verbose("Enrichment result not stored for message id " + messageId); + return; + } + if (res.sender !== undefined) { + completionHandler.onSuccess(res); + } + else { + completionHandler.onError(res); + } + this.completionOrderList.shift(); + delete this.messageIdToCompletionHandlers[messageId]; + delete this.enrichedMessagesAwaitingCompletionCalls[messageId]; + } while (this.completionOrderList[0] !== undefined && + this.enrichedMessagesAwaitingCompletionCalls[this.completionOrderList[0]] !== undefined); + }; + return BasicMessageEnricher; +}()); +exports.default = BasicMessageEnricher; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var CursorSubscription = (function () { + function CursorSubscription(options) { + this.delegate = options.delegate; + this.logger = options.logger; + this.room = options.room; + this.userStore = options.userStore; + this.handleCursorSetInternal = options.handleCursorSetInternal; + } + CursorSubscription.prototype.handleEvent = function (event) { + var _this = this; + if (!this.delegate || !this.delegate.cursorSet) { + return; + } + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + if (eventName !== 'cursor_set') { + this.logger.verbose("Cursor subscription received event with type " + eventName + ", when 'cursor_set' was expected"); + return; + } + this.logger.verbose("Received event name: " + eventName + ", and data: " + data); + var basicCursor = payload_deserializer_1.default.createBasicCursorFromPayload(data); + this.logger.verbose("Room received cursor for: " + basicCursor.userId); + this.handleCursorSetInternal(basicCursor); + this.enrich(basicCursor, function (cursor) { + if (_this.delegate && _this.delegate.cursorSet) { + _this.delegate.cursorSet(cursor); + } + }, function (error) { + _this.logger.debug('Error receiving cursor:', error); + }); + }; + CursorSubscription.prototype.enrich = function (basicCursor, onSuccess, onError) { + var _this = this; + this.userStore.user(basicCursor.userId, function (user) { + onSuccess({ + cursorType: basicCursor.cursorType, + position: basicCursor.position, + room: _this.room, + updatedAt: basicCursor.updatedAt, + user: user, + }); + }, function (error) { + _this.logger.debug("Unable to find user with id " + basicCursor.userId + ". Error:", error); + onError(error); + }); + }; + return CursorSubscription; +}()); +exports.default = CursorSubscription; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var CursorType; +(function (CursorType) { + CursorType[CursorType["Read"] = 0] = "Read"; +})(CursorType || (CursorType = {})); +exports.default = CursorType; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var PresenceSubscription = (function () { + function PresenceSubscription(options) { + this.apiInstance = options.apiInstance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.delegate = options.delegate; + } + PresenceSubscription.prototype.handleEvent = function (event) { + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + this.apiInstance.logger.verbose("Received event type: " + eventName + ", and data: " + data); + switch (eventName) { + case 'initial_state': + this.parseInitialStatePayload(eventName, data, this.userStore); + break; + case 'presence_update': + this.parsePresenceUpdatePayload(eventName, data, this.userStore); + break; + case 'join_room_presence_update': + this.parseJoinRoomPresenceUpdatePayload(eventName, data, this.userStore); + break; + default: + this.apiInstance.logger.verbose("Unsupported event type received: " + eventName + ", and data: " + data); + break; + } + }; + PresenceSubscription.prototype.end = function () { + }; + PresenceSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { + var _this = this; + var userStatesPayload = data.user_states; + if (userStatesPayload === undefined || + userStatesPayload.constructor !== Array) { + this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); + return; + } + var userStates = userStatesPayload + .map(function (userStatePayload) { + return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); + }) + .filter(function (el) { return el !== undefined; }); + if (userStates.length === 0) { + this.apiInstance.logger.verbose('No presence user states to process'); + return; + } + this.userStore.handleInitialPresencePayloads(userStates, function () { + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }); + }; + PresenceSubscription.prototype.parsePresenceUpdatePayload = function (eventName, data, userStore) { + var _this = this; + var presencePayload = payload_deserializer_1.default.createPresencePayloadFromPayload(data); + userStore.user(presencePayload.userId, function (user) { + user.updatePresenceInfoIfAppropriate(presencePayload); + switch (presencePayload.state.stringValue) { + case 'online': + if (_this.delegate && _this.delegate.userCameOnline) { + _this.delegate.userCameOnline(user); + } + _this.apiInstance.logger.verbose(user.id + " came online"); + break; + case 'offline': + if (_this.delegate && _this.delegate.userWentOffline) { + _this.delegate.userWentOffline(user); + } + _this.apiInstance.logger.verbose(user.id + " went offline"); + break; + case 'unknown': + _this.apiInstance.logger.verbose("Somehow the presence state of user " + user.id + " is unknown"); + break; + } + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + return; + } + if (room.userIds.indexOf(user.id) > -1) { + switch (presencePayload.state.stringValue) { + case 'online': + if (room.subscription.delegate && + room.subscription.delegate.userCameOnlineInRoom) { + room.subscription.delegate.userCameOnlineInRoom(user); + } + break; + case 'offline': + if (room.subscription.delegate && + room.subscription.delegate.userWentOfflineInRoom) { + room.subscription.delegate.userWentOfflineInRoom(user); + } + break; + default: + break; + } + } + }); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching user information for user with id " + presencePayload.userId + ":", error); + return; + }); + }; + PresenceSubscription.prototype.parseJoinRoomPresenceUpdatePayload = function (eventName, data, userStore) { + var _this = this; + var userStatesPayload = data.user_states; + if (userStatesPayload === undefined || + userStatesPayload.constructor !== Array) { + this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); + return; + } + var userStates = userStatesPayload + .map(function (userStatePayload) { + return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); + }) + .filter(function (el) { return el !== undefined; }); + if (userStates.length === 0) { + this.apiInstance.logger.verbose('No presence user states to process'); + return; + } + this.userStore.handleInitialPresencePayloads(userStates, function () { + _this.roomStore.rooms.forEach(function (room) { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }); + }; + return PresenceSubscription; +}()); +exports.default = PresenceSubscription; + + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var RoomStore = (function () { + function RoomStore(options) { + this.rooms = options.rooms; + this.apiInstance = options.apiInstance; + } + RoomStore.prototype.room = function (id, onSuccess, onError) { + this.findOrGetRoom(id, onSuccess, onError); + }; + RoomStore.prototype.addOrMerge = function (room) { + var existingRoom = this.rooms.find(function (el) { return el.id === room.id; }); + if (existingRoom) { + existingRoom.updateWithPropertiesOfRoom(room); + return existingRoom; + } + else { + this.rooms.push(room); + return room; + } + }; + RoomStore.prototype.remove = function (id) { + var indexOfRoom = this.rooms.findIndex(function (el) { return el.id === id; }); + if (indexOfRoom === -1) { + return undefined; + } + var room = this.rooms[indexOfRoom]; + this.rooms.splice(indexOfRoom, 1); + return room; + }; + RoomStore.prototype.findOrGetRoom = function (id, onSuccess, onError) { + var room = this.rooms.find(function (el) { return el.id === id; }); + if (room) { + onSuccess(room); + } + else { + this.getRoom(id, onSuccess, onError); + } + }; + RoomStore.prototype.getRoom = function (id, onSuccess, onError) { + var _this = this; + this.apiInstance + .request({ + method: 'GET', + path: "/rooms/" + id, + }) + .then(function (res) { + var roomPayload = JSON.parse(res); + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + onSuccess(room); + }) + .catch(function (error) { + _this.apiInstance.logger.debug("Error fetching room " + id + ":", error); + onError(error); + }); + }; + return RoomStore; +}()); +exports.default = RoomStore; + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var RoomSubscription = (function () { + function RoomSubscription(options) { + this.delegate = options.delegate; + this.basicMessageEnricher = options.basicMessageEnricher; + this.logger = options.logger; + } + RoomSubscription.prototype.handleEvent = function (event) { + var _this = this; + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + if (eventName !== 'new_message') { + this.logger.verbose("Room subscription received event with type " + eventName + ", when 'new_message' was expected"); + return; + } + this.logger.verbose("Received event name: " + eventName + ", and data:", data); + var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(data); + this.basicMessageEnricher.enrich(basicMessage, function (message) { + _this.logger.verbose("Room received new message: " + message.text); + if (_this.delegate && _this.delegate.newMessage) { + _this.delegate.newMessage(message); + } + }, function (error) { + _this.logger.debug('Error receiving new message:', error); + }); + }; + return RoomSubscription; +}()); +exports.default = RoomSubscription; + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var room_user_store_1 = __webpack_require__(19); +var Room = (function () { + function Room(options) { + this.id = options.id; + this.name = options.name; + this.isPrivate = options.isPrivate; + this.createdByUserId = options.createdByUserId; + this.createdAt = options.createdAt; + this.updatedAt = options.updatedAt; + this.deletedAt = options.deletedAt; + this.userIds = options.userIds || []; + this.userStore = new room_user_store_1.default(); + } + Room.prototype.updateWithPropertiesOfRoom = function (room) { + this.name = room.name; + this.isPrivate = room.isPrivate; + this.updatedAt = room.updatedAt; + this.deletedAt = room.deletedAt; + this.userIds = room.userIds; + }; + return Room; +}()); +exports.default = Room; + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var user_store_core_1 = __webpack_require__(5); +var RoomUserStore = (function () { + function RoomUserStore(userStoreCore) { + if (userStoreCore === void 0) { userStoreCore = new user_store_core_1.default(); } + this.userStoreCore = userStoreCore; + } + RoomUserStore.prototype.addOrMerge = function (user) { + return this.userStoreCore.addOrMerge(user); + }; + RoomUserStore.prototype.remove = function (id) { + return this.userStoreCore.remove(id); + }; + return RoomUserStore; +}()); +exports.default = RoomUserStore; + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var presence_state_1 = __webpack_require__(4); +var User = (function () { + function User(options) { + this.id = options.id; + this.createdAt = options.createdAt; + this.updatedAt = options.updatedAt; + this.name = options.name; + this.avatarURL = options.avatarURL; + this.customData = options.customData; + this.presenceState = new presence_state_1.default('unknown'); + } + User.prototype.updateWithPropertiesOfUser = function (user) { + if (user.presenceState.stringValue !== 'unknown') { + this.presenceState = user.presenceState; + this.lastSeenAt = user.lastSeenAt; + } + return this; + }; + User.prototype.updatePresenceInfoIfAppropriate = function (newInfoPayload) { + if (newInfoPayload.state.stringValue !== 'unknown') { + this.presenceState = newInfoPayload.state; + this.lastSeenAt = newInfoPayload.lastSeenAt; + } + }; + return User; +}()); +exports.default = User; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var payload_deserializer_1 = __webpack_require__(0); +var constants_1 = __webpack_require__(3); +var utils_1 = __webpack_require__(1); +var UserSubscription = (function () { + function UserSubscription(options) { + this.typingTimers = {}; + this.apiInstance = options.apiInstance; + this.filesInstance = options.filesInstance; + this.cursorsInstance = options.cursorsInstance; + this.userStore = options.userStore; + this.delegate = options.delegate; + this.connectCompletionHandlers = [options.connectCompletionHandler]; + } + UserSubscription.prototype.handleEvent = function (event) { + var body = event.body, eventId = event.eventId, headers = event.headers; + var data = body.data; + var eventName = body.event_name; + this.apiInstance.logger.verbose("Received event name: " + eventName + ", and data: " + data); + switch (eventName) { + case 'initial_state': + this.parseInitialStatePayload(eventName, data, this.userStore); + break; + case 'added_to_room': + this.parseAddedToRoomPayload(eventName, data); + break; + case 'removed_from_room': + this.parseRemovedFromRoomPayload(eventName, data); + break; + case 'room_updated': + this.parseRoomUpdatedPayload(eventName, data); + break; + case 'room_deleted': + this.parseRoomDeletedPayload(eventName, data); + break; + case 'user_joined': + this.parseUserJoinedPayload(eventName, data); + break; + case 'user_left': + this.parseUserLeftPayload(eventName, data); + break; + case 'typing_start': + this.parseIsTypingPayload(eventName, data, data.user_id); + break; + case 'typing_stop': + break; + } + }; + UserSubscription.prototype.callConnectCompletionHandlers = function (currentUser, error) { + this.connectCompletionHandlers.forEach(function (completionHandler) { + completionHandler(currentUser, error); + }); + }; + UserSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { + var _this = this; + var roomsPayload = data.rooms; + var userPayload = data.current_user; + var receivedCurrentUser = payload_deserializer_1.default.createCurrentUserFromPayload(userPayload, this.apiInstance, this.filesInstance, this.cursorsInstance, this.userStore); + var wasExistingCurrentUser = this.currentUser !== undefined; + if (this.currentUser) { + this.currentUser.updateWithPropertiesOf(receivedCurrentUser); + } + else { + this.currentUser = receivedCurrentUser; + } + var receivedRoomsConstructor = roomsPayload.constructor; + if (receivedRoomsConstructor !== Array) { + throw TypeError('`rooms` key of initial_state payload was of type `${receivedRoomsConstructor}`, expected `Array`'); + } + if (roomsPayload.length === 0) { + this.currentUser.setupPresenceSubscription(this.delegate); + this.callConnectCompletionHandlers(this.currentUser); + return; + } + var combinedRoomUserIds = new Set([]); + var roomsFromConnection = []; + roomsPayload.forEach(function (roomPayload) { + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + room.userIds.forEach(function (userId) { + combinedRoomUserIds.add(userId); + }); + roomsFromConnection.push(room); + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.roomStore.addOrMerge(room); + }); + this.callConnectCompletionHandlers(this.currentUser); + this.fetchInitialUserInformationForUserIds(combinedRoomUserIds, this.currentUser); + if (wasExistingCurrentUser) { + this.reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection); + } + }; + UserSubscription.prototype.fetchInitialUserInformationForUserIds = function (userIds, currentUser) { + var _this = this; + var userIdsArray = Array.from(userIds.values()); + this.userStore.initialFetchOfUsersWithIds(userIdsArray, function (users) { + var combinedRoomUsersPromises = new Array(); + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.roomStore.rooms.forEach(function (room) { + var roomPromise = new Promise(function (roomResolve, roomReject) { + var roomUsersPromises = new Array(); + room.userIds.forEach(function (userId) { + var userPromise = new Promise(function (userResolve, userReject) { + _this.userStore.user(userId, function (user) { + room.userStore.addOrMerge(user); + userResolve(); + }, function (error) { + _this.apiInstance.logger.verbose("Unable to fetch information about user " + userId); + userReject(); + }); + }); + roomUsersPromises.push(userPromise); + }); + utils_1.allPromisesSettled(roomUsersPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name + "\""); + roomResolve(); + }); + }); + combinedRoomUsersPromises.push(roomPromise); + }); + utils_1.allPromisesSettled(combinedRoomUsersPromises).then(function () { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.setupPresenceSubscription(_this.delegate); + }); + }, function (error) { + _this.apiInstance.logger.debug("Unable to fetch user information after successful connection: " + error); + return; + }); + }; + UserSubscription.prototype.reconcileExistingRoomStoreWithRoomsReceivedOnConnection = function (roomsFromConnection) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property of UserSubscription unset after successful connection'); + return; + } + var roomStoreRooms = this.currentUser.roomStore.rooms; + var mostRecentConnectionRoomsSet = new Set(roomsFromConnection); + var noLongerAMemberOfRooms = roomStoreRooms.filter(function (room) { return !mostRecentConnectionRoomsSet.has(room); }); + noLongerAMemberOfRooms.forEach(function (room) { + if (_this.delegate && _this.delegate.removedFromRoom) { + _this.delegate.removedFromRoom(room); + } + }); + }; + UserSubscription.prototype.parseAddedToRoomPayload = function (eventName, data) { + var _this = this; + var roomPayload = data.room; + if (roomPayload === undefined || typeof roomPayload !== 'object') { + this.apiInstance.logger.verbose("`room` key missing or invalid in `added_to_room` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + var roomAdded = this.currentUser.roomStore.addOrMerge(room); + if (this.delegate && this.delegate.addedToRoom) { + this.delegate.addedToRoom(room); + } + this.apiInstance.logger.verbose("Added to room: " + room.name); + var roomUsersPromises = new Array(); + roomAdded.userIds.forEach(function (userId) { + var userPromise = new Promise(function (resolve, reject) { + _this.userStore.user(userId, function (user) { + _this.apiInstance.logger.verbose("Added user id " + userId + " to room " + room.name); + room.userStore.addOrMerge(user); + resolve(); + }, function (error) { + _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room " + room.name + ": " + error); + reject(); + }); + }); + roomUsersPromises.push(userPromise); + }); + utils_1.allPromisesSettled(roomUsersPromises).then(function () { + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.usersUpdated) { + room.subscription.delegate.usersUpdated(); + } + } + _this.apiInstance.logger.verbose("Users updated in room " + room.name); + }); + }; + UserSubscription.prototype.parseRemovedFromRoomPayload = function (eventName, data) { + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `removed_from_room` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var roomRemoved = this.currentUser.roomStore.remove(roomId); + if (roomRemoved) { + if (this.delegate && this.delegate.removedFromRoom) { + this.delegate.removedFromRoom(roomRemoved); + } + this.apiInstance.logger.verbose("Removed from room: " + roomRemoved.name); + } + else { + this.apiInstance.logger.verbose("Received `removed_from_room` API event but room with ID " + roomId + " not found in local store of joined rooms"); + return; + } + }; + UserSubscription.prototype.parseRoomUpdatedPayload = function (eventName, data) { + var _this = this; + var roomPayload = data.room; + if (roomPayload === undefined || typeof roomPayload !== 'object') { + this.apiInstance.logger.verbose("`room` key missing or invalid in `room_updated` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); + this.currentUser.roomStore.room(room.id, function (roomToUpdate) { + roomToUpdate.updateWithPropertiesOfRoom(room); + if (_this.delegate && _this.delegate.roomUpdated) { + _this.delegate.roomUpdated(roomToUpdate); + } + _this.apiInstance.logger.verbose("Room updated: " + room.name); + }, function (error) { + _this.apiInstance.logger.debug("Error updating room " + room.id + ":", error); + }); + }; + UserSubscription.prototype.parseRoomDeletedPayload = function (eventName, data) { + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `room_deleted` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + var deletedRoom = this.currentUser.roomStore.remove(roomId); + if (deletedRoom) { + if (this.delegate && this.delegate.roomDeleted) { + this.delegate.roomDeleted(deletedRoom); + } + this.apiInstance.logger.verbose("Room deleted: " + deletedRoom.name); + } + else { + this.apiInstance.logger.verbose("Received `room_deleted` API event but room with ID " + roomId + " not found in local store of joined rooms"); + return; + } + }; + UserSubscription.prototype.parseUserJoinedPayload = function (eventName, data) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_joined` payload: " + data); + return; + } + var userId = data.user_id; + if (userId === undefined || typeof userId !== 'string') { + this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_joined` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + var addedOrMergedUser = room.userStore.addOrMerge(user); + if (room.userIds.indexOf(addedOrMergedUser.id) === -1) { + room.userIds.push(addedOrMergedUser.id); + } + if (_this.delegate && _this.delegate.userJoinedRoom) { + _this.delegate.userJoinedRoom(room, addedOrMergedUser); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userJoined) { + room.subscription.delegate.userJoined(addedOrMergedUser); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " joined room: " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); + return; + }); + }; + UserSubscription.prototype.parseUserLeftPayload = function (eventName, data) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_left` payload: " + data); + return; + } + var userId = data.user_id; + if (userId === undefined || typeof userId !== 'string') { + this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_left` payload: " + data); + return; + } + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + var roomUserIdIndex = room.userIds.indexOf(user.id); + if (roomUserIdIndex > -1) { + room.userIds.splice(roomUserIdIndex, 1); + } + room.userStore.remove(user.id); + if (_this.delegate && _this.delegate.userLeftRoom) { + _this.delegate.userLeftRoom(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userLeft) { + room.subscription.delegate.userLeft(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " left room " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " left room with id " + roomId + " but no information about the user could be retrieved. Error was: " + error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); + return; + }); + }; + UserSubscription.prototype.parseIsTypingPayload = function (eventName, data, userId) { + var _this = this; + var roomId = data.room_id; + if (roomId === undefined || typeof roomId !== 'number') { + this.apiInstance.logger.verbose("`room_id` key missing or invalid in `typing_start` payload: " + data); + return; + } + if (!this.typingTimers[roomId]) { + this.typingTimers[roomId] = {}; + } + if (this.typingTimers[roomId][userId]) { + clearTimeout(this.typingTimers[roomId][userId]); + } + else { + this.startedTyping(roomId, userId); + } + this.typingTimers[roomId][userId] = setTimeout(function () { + _this.stoppedTyping(roomId, userId); + delete _this.typingTimers[roomId][userId]; + }, constants_1.TYPING_REQ_TTL); + }; + UserSubscription.prototype.startedTyping = function (roomId, userId) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + if (_this.delegate && _this.delegate.userStartedTyping) { + _this.delegate.userStartedTyping(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userStartedTyping) { + room.subscription.delegate.userStartedTyping(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " started typing in room " + room.name); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching information for user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.verbose("Error fetching information for room " + roomId + ":", error); + return; + }); + }; + UserSubscription.prototype.stoppedTyping = function (roomId, userId) { + var _this = this; + if (!this.currentUser) { + this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + this.currentUser.roomStore.room(roomId, function (room) { + if (!_this.currentUser) { + _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); + return; + } + _this.currentUser.userStore.user(userId, function (user) { + if (_this.delegate && _this.delegate.userStoppedTyping) { + _this.delegate.userStoppedTyping(room, user); + } + if (room.subscription === undefined) { + _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); + } + else { + if (room.subscription.delegate && + room.subscription.delegate.userStoppedTyping) { + room.subscription.delegate.userStoppedTyping(user); + } + } + _this.apiInstance.logger.verbose("User " + user.id + " stopped typing in room " + room.name); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching information for user " + userId + ":", error); + return; + }); + }, function (error) { + _this.apiInstance.logger.debug("Error fetching information for room " + roomId + ":", error); + return; + }); + }; + return UserSubscription; +}()); +exports.default = UserSubscription; + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/dist/worker/declarations/attachment.d.ts b/dist/worker/declarations/attachment.d.ts new file mode 100644 index 0000000..1e89409 --- /dev/null +++ b/dist/worker/declarations/attachment.d.ts @@ -0,0 +1,6 @@ +interface Attachment { + fetchRequired: boolean; + link: string; + type: string; +} +export default Attachment; diff --git a/dist/worker/declarations/basic_cursor.d.ts b/dist/worker/declarations/basic_cursor.d.ts new file mode 100644 index 0000000..1ab80b5 --- /dev/null +++ b/dist/worker/declarations/basic_cursor.d.ts @@ -0,0 +1,8 @@ +interface BasicCursor { + cursorType: number; + position: number; + roomId: number; + updatedAt: string; + userId: string; +} +export default BasicCursor; diff --git a/dist/worker/declarations/basic_message.d.ts b/dist/worker/declarations/basic_message.d.ts new file mode 100644 index 0000000..b28e155 --- /dev/null +++ b/dist/worker/declarations/basic_message.d.ts @@ -0,0 +1,11 @@ +import Attachment from './attachment'; +interface BasicMessage { + id: number; + senderId: string; + roomId: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; +} +export default BasicMessage; diff --git a/dist/worker/declarations/basic_message_enricher.d.ts b/dist/worker/declarations/basic_message_enricher.d.ts new file mode 100644 index 0000000..a8f7e15 --- /dev/null +++ b/dist/worker/declarations/basic_message_enricher.d.ts @@ -0,0 +1,38 @@ +import { Logger } from 'pusher-platform'; +import BasicMessage from './basic_message'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import Room from './room'; +import User from './user'; +export interface MessageEnrichmentCompletionHandlers { + onSuccess: (message: Message) => void; + onError: (error: any) => void; +} +export declare type MessageIdsToCompletionHandlers = { + [key: number]: MessageEnrichmentCompletionHandlers; +}; +export declare type UserIdsToBasicMessageIds = { + [key: string]: number[]; +}; +export declare type MessageEnrichmentResult = Message | any; +export declare type MessageIdsToEnrichmentResults = { + [key: number]: MessageEnrichmentResult; +}; +export declare type MessageIdsToBasicMessages = { + [key: number]: BasicMessage; +}; +export default class BasicMessageEnricher { + userStore: GlobalUserStore; + room: Room; + logger: Logger; + private completionOrderList; + private messageIdToCompletionHandlers; + private enrichedMessagesAwaitingCompletionCalls; + private userIdsBeingRetrieved; + private userIdsToBasicMessageIds; + private messagesAwaitingEnrichmentDependentOnUserRetrieval; + constructor(userStore: GlobalUserStore, room: Room, logger: Logger); + enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; + enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; + callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; +} diff --git a/dist/worker/declarations/basic_user.d.ts b/dist/worker/declarations/basic_user.d.ts new file mode 100644 index 0000000..fb90490 --- /dev/null +++ b/dist/worker/declarations/basic_user.d.ts @@ -0,0 +1,6 @@ +interface BasicUser { + id: string; + createdAt: string; + updatedAt: string; +} +export default BasicUser; diff --git a/dist/worker/declarations/chat_manager.d.ts b/dist/worker/declarations/chat_manager.d.ts new file mode 100644 index 0000000..49a8817 --- /dev/null +++ b/dist/worker/declarations/chat_manager.d.ts @@ -0,0 +1,25 @@ +import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +export interface ChatManagerOptions { + instanceLocator: string; + tokenProvider: TokenProvider; + logger?: Logger; + baseClient?: BaseClient; + userId: string; +} +export default class ChatManager { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userId: string; + private userStore; + private userSubscription; + constructor(options: ChatManagerOptions); + connect(options: ConnectOptions): void; +} +export interface ConnectOptions { + delegate?: ChatManagerDelegate; + onSuccess: (currentUser: CurrentUser) => void; + onError: (error: any) => void; +} diff --git a/dist/worker/declarations/chat_manager_delegate.d.ts b/dist/worker/declarations/chat_manager_delegate.d.ts new file mode 100644 index 0000000..5b2d790 --- /dev/null +++ b/dist/worker/declarations/chat_manager_delegate.d.ts @@ -0,0 +1,16 @@ +import Room from './room'; +import User from './user'; +interface ChatManagerDelegate { + addedToRoom?: (room: Room) => void; + removedFromRoom?: (room: Room) => void; + roomUpdated?: (room: Room) => void; + roomDeleted?: (room: Room) => void; + userStartedTyping?: (room: Room, user: User) => void; + userStoppedTyping?: (room: Room, user: User) => void; + userJoinedRoom?: (room: Room, user: User) => void; + userLeftRoom?: (room: Room, user: User) => void; + userCameOnline?: (user: User) => void; + userWentOffline?: (user: User) => void; + error?: (error: any) => void; +} +export default ChatManagerDelegate; diff --git a/dist/worker/declarations/constants.d.ts b/dist/worker/declarations/constants.d.ts new file mode 100644 index 0000000..d18fd38 --- /dev/null +++ b/dist/worker/declarations/constants.d.ts @@ -0,0 +1,2 @@ +export declare const TYPING_REQ_TTL = 1500; +export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/worker/declarations/current_user.d.ts b/dist/worker/declarations/current_user.d.ts new file mode 100644 index 0000000..77a8eae --- /dev/null +++ b/dist/worker/declarations/current_user.d.ts @@ -0,0 +1,111 @@ +import { Instance } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import Message from './message'; +import PresenceSubscription from './presence_subscription'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +import RoomStore from './room_store'; +export interface CreateRoomOptions { + name: string; + private?: boolean; + addUserIds?: string[]; +} +export interface UpdateRoomOptions { + name?: string; + isPrivate?: boolean; +} +export interface FetchRoomMessagesOptions { + initialId?: string; + limit?: number; + direction?: string; +} +export interface CurrentUserOptions { + id: string; + createdAt: string; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + rooms?: Room[]; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; +} +export interface DataAttachment { + file: Blob; + name: string; +} +export interface LinkAttachment { + link: string; + type: string; +} +export declare type GenericAttachment = LinkAttachment | DataAttachment; +export interface AttachmentBody { + resource_link: string; + type: string; +} +export interface SendMessageOptions { + attachment?: GenericAttachment; + roomId: number; + text?: string; +} +export interface CompleteMessageOptions { + attachment?: AttachmentBody; + roomId: number; + text?: string; + user_id: string; +} +export default class CurrentUser { + id: string; + createdAt: string; + cursors: { + [roomId: string]: BasicCursor; + }; + cursorsReq: Promise; + updatedAt: string; + name?: string; + avatarURL?: string; + customData?: any; + userStore: GlobalUserStore; + roomStore: RoomStore; + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + pathFriendlyId: string; + presenceSubscription: PresenceSubscription; + typingRequestSent: { + [roomId: string]: number; + }; + readonly rooms: Room[]; + constructor(options: CurrentUserOptions); + updateWithPropertiesOf(currentUser: CurrentUser): void; + setupPresenceSubscription(delegate?: ChatManagerDelegate): void; + createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + populateRoomUserStore(room: Room): void; + addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; + deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; + joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; + leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; + isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; + setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; + sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; + subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; + fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; + fetchAttachment(attachmentURL: string): Promise; + private isDataAttachment(attachment); + private isLinkAttachment(attachment); + private uploadFile(file, fileName, roomId); + private sendMessageWithCompleteOptions(options, onSuccess, onError); + private subscribeToCursors(room, roomDelegate); + private getRooms(path, onSuccess, onError); +} diff --git a/dist/worker/declarations/cursor.d.ts b/dist/worker/declarations/cursor.d.ts new file mode 100644 index 0000000..3aa3524 --- /dev/null +++ b/dist/worker/declarations/cursor.d.ts @@ -0,0 +1,10 @@ +import Room from './room'; +import User from './user'; +interface Cursor { + cursorType: number; + position: number; + room: Room; + updatedAt: string; + user: User; +} +export default Cursor; diff --git a/dist/worker/declarations/cursor_subscription.d.ts b/dist/worker/declarations/cursor_subscription.d.ts new file mode 100644 index 0000000..08e991b --- /dev/null +++ b/dist/worker/declarations/cursor_subscription.d.ts @@ -0,0 +1,23 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicCursor from './basic_cursor'; +import Cursor from './cursor'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +import RoomDelegate from './room_delegate'; +export interface CursorSubscriptionOptions { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; +} +export default class CursorSubscription { + delegate?: RoomDelegate; + logger: Logger; + room: Room; + userStore: GlobalUserStore; + handleCursorSetInternal: (cursor: BasicCursor) => void; + constructor(options: CursorSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; +} diff --git a/dist/worker/declarations/cursor_types.d.ts b/dist/worker/declarations/cursor_types.d.ts new file mode 100644 index 0000000..01f22f7 --- /dev/null +++ b/dist/worker/declarations/cursor_types.d.ts @@ -0,0 +1,4 @@ +declare enum CursorType { + Read = 0, +} +export default CursorType; diff --git a/dist/worker/declarations/fetched_attachment.d.ts b/dist/worker/declarations/fetched_attachment.d.ts new file mode 100644 index 0000000..907eddc --- /dev/null +++ b/dist/worker/declarations/fetched_attachment.d.ts @@ -0,0 +1,11 @@ +export interface FetchedAttachmentFile { + bytes: number; + lastModified: number; + name: string; +} +interface FetchedAttachment { + file: FetchedAttachmentFile; + link: string; + ttl: number; +} +export default FetchedAttachment; diff --git a/dist/worker/declarations/global_user_store.d.ts b/dist/worker/declarations/global_user_store.d.ts new file mode 100644 index 0000000..7712fe4 --- /dev/null +++ b/dist/worker/declarations/global_user_store.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import PresencePayload from './presence_payload'; +import User from './user'; +import UserStoreCore from './user_store_core'; +export interface GlobalUserStoreOptions { + apiInstance: Instance; + userStoreCore?: UserStoreCore; +} +export default class GlobalUserStore { + private apiInstance; + private userStoreCore; + constructor(options: GlobalUserStoreOptions); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; + handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; + handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; + fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; + initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; +} diff --git a/dist/worker/declarations/index.d.ts b/dist/worker/declarations/index.d.ts new file mode 100644 index 0000000..8118af7 --- /dev/null +++ b/dist/worker/declarations/index.d.ts @@ -0,0 +1,10 @@ +import { BaseClient } from 'pusher-platform'; +import ChatManager from './chat_manager'; +import TokenProvider from './token_provider'; +export { BaseClient, ChatManager, TokenProvider }; +declare const _default: { + BaseClient: typeof BaseClient; + ChatManager: typeof ChatManager; + TokenProvider: typeof TokenProvider; +}; +export default _default; diff --git a/dist/worker/declarations/message.d.ts b/dist/worker/declarations/message.d.ts new file mode 100644 index 0000000..d7bd58d --- /dev/null +++ b/dist/worker/declarations/message.d.ts @@ -0,0 +1,13 @@ +import Attachment from './attachment'; +import Room from './room'; +import User from './user'; +interface Message { + id: number; + text: string; + createdAt: string; + updatedAt: string; + attachment?: Attachment; + sender: User; + room: Room; +} +export default Message; diff --git a/dist/worker/declarations/payload_deserializer.d.ts b/dist/worker/declarations/payload_deserializer.d.ts new file mode 100644 index 0000000..bb635f2 --- /dev/null +++ b/dist/worker/declarations/payload_deserializer.d.ts @@ -0,0 +1,22 @@ +import { Instance } from 'pusher-platform'; +import Attachment from './attachment'; +import BasicCursor from './basic_cursor'; +import BasicMessage from './basic_message'; +import BasicUser from './basic_user'; +import CurrentUser from './current_user'; +import FetchedAttachment from './fetched_attachment'; +import GlobalUserStore from './global_user_store'; +import PresencePayload from './presence_payload'; +import Room from './room'; +import User from './user'; +export default class PayloadDeserializer { + static createUserFromPayload(userPayload: any): User; + static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; + static createRoomFromPayload(roomPayload: any): Room; + static createBasicMessageFromPayload(messagePayload: any): BasicMessage; + static createBasicCursorFromPayload(payload: any): BasicCursor; + static createPresencePayloadFromPayload(payload: any): PresencePayload; + static createBasicUserFromPayload(payload: any): BasicUser; + static createAttachmentFromPayload(payload: any): Attachment | undefined; + static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; +} diff --git a/dist/worker/declarations/presence_payload.d.ts b/dist/worker/declarations/presence_payload.d.ts new file mode 100644 index 0000000..c2a2215 --- /dev/null +++ b/dist/worker/declarations/presence_payload.d.ts @@ -0,0 +1,7 @@ +import PresenceState from './presence_state'; +interface PresencePayload { + userId: string; + state: PresenceState; + lastSeenAt?: string; +} +export default PresencePayload; diff --git a/dist/worker/declarations/presence_state.d.ts b/dist/worker/declarations/presence_state.d.ts new file mode 100644 index 0000000..b7bd7d0 --- /dev/null +++ b/dist/worker/declarations/presence_state.d.ts @@ -0,0 +1,4 @@ +export default class PresenceState { + stringValue: string; + constructor(state: string); +} diff --git a/dist/worker/declarations/presence_subscription.d.ts b/dist/worker/declarations/presence_subscription.d.ts new file mode 100644 index 0000000..53583cc --- /dev/null +++ b/dist/worker/declarations/presence_subscription.d.ts @@ -0,0 +1,22 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import GlobalUserStore from './global_user_store'; +import RoomStore from './room_store'; +export interface PresenceSubscriptionOptions { + apiInstance: Instance; + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; +} +export default class PresenceSubscription { + userStore: GlobalUserStore; + roomStore: RoomStore; + delegate?: ChatManagerDelegate; + private apiInstance; + constructor(options: PresenceSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + end(): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; +} diff --git a/dist/worker/declarations/room.d.ts b/dist/worker/declarations/room.d.ts new file mode 100644 index 0000000..f62e355 --- /dev/null +++ b/dist/worker/declarations/room.d.ts @@ -0,0 +1,28 @@ +import CursorSubscription from './cursor_subscription'; +import RoomSubscription from './room_subscription'; +import RoomUserStore from './room_user_store'; +export interface RoomOptions { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds?: string[]; +} +export default class Room { + id: number; + name: string; + isPrivate: boolean; + createdByUserId: string; + createdAt: string; + updatedAt: string; + deletedAt?: string; + userIds: string[]; + userStore: RoomUserStore; + subscription?: RoomSubscription; + cursorSubscription?: CursorSubscription; + constructor(options: RoomOptions); + updateWithPropertiesOfRoom(room: Room): void; +} diff --git a/dist/worker/declarations/room_delegate.d.ts b/dist/worker/declarations/room_delegate.d.ts new file mode 100644 index 0000000..fbfb142 --- /dev/null +++ b/dist/worker/declarations/room_delegate.d.ts @@ -0,0 +1,16 @@ +import Cursor from './cursor'; +import Message from './message'; +import User from './user'; +interface RoomDelegate { + newMessage?: (message: Message) => void; + userStartedTyping?: (user: User) => void; + userStoppedTyping?: (user: User) => void; + userJoined?: (user: User) => void; + userLeft?: (user: User) => void; + userCameOnlineInRoom?: (user: User) => void; + userWentOfflineInRoom?: (user: User) => void; + usersUpdated?: () => void; + error?: (error: any) => void; + cursorSet?: (cursor: Cursor) => void; +} +export default RoomDelegate; diff --git a/dist/worker/declarations/room_store.d.ts b/dist/worker/declarations/room_store.d.ts new file mode 100644 index 0000000..9d9befa --- /dev/null +++ b/dist/worker/declarations/room_store.d.ts @@ -0,0 +1,16 @@ +import { Instance } from 'pusher-platform'; +import Room from './room'; +export interface RoomStoreOptions { + rooms: Room[]; + apiInstance: Instance; +} +export default class RoomStore { + rooms: Room[]; + apiInstance: Instance; + constructor(options: RoomStoreOptions); + room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + addOrMerge(room: Room): Room; + remove(id: number): Room | undefined; + findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; + getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; +} diff --git a/dist/worker/declarations/room_subscription.d.ts b/dist/worker/declarations/room_subscription.d.ts new file mode 100644 index 0000000..c37121a --- /dev/null +++ b/dist/worker/declarations/room_subscription.d.ts @@ -0,0 +1,15 @@ +import { Logger, SubscriptionEvent } from 'pusher-platform'; +import BasicMessageEnricher from './basic_message_enricher'; +import RoomDelegate from './room_delegate'; +export interface RoomSubscriptionOptions { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; +} +export default class RoomSubscription { + delegate?: RoomDelegate; + basicMessageEnricher: BasicMessageEnricher; + logger: Logger; + constructor(options: RoomSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; +} diff --git a/dist/worker/declarations/room_user_store.d.ts b/dist/worker/declarations/room_user_store.d.ts new file mode 100644 index 0000000..eb1f60f --- /dev/null +++ b/dist/worker/declarations/room_user_store.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +import UserStoreCore from './user_store_core'; +export default class RoomUserStore { + private userStoreCore; + constructor(userStoreCore?: UserStoreCore); + addOrMerge(user: User): User; + remove(id: string): User | undefined; +} diff --git a/dist/worker/declarations/token_provider.d.ts b/dist/worker/declarations/token_provider.d.ts new file mode 100644 index 0000000..5fb85e9 --- /dev/null +++ b/dist/worker/declarations/token_provider.d.ts @@ -0,0 +1,29 @@ +import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; +export interface TokenProviderAuthContextOptions { + queryParams?: TokenProviderAuthContextQueryParams; + headers?: TokenProviderAuthContextHeaders; +} +export declare type TokenProviderAuthContextHeaders = { + [key: string]: string; +}; +export declare type TokenProviderAuthContextQueryParams = { + [key: string]: string; +}; +export interface TokenProviderOptions { + authContext?: TokenProviderAuthContextOptions; + url: string; +} +export default class TokenProvider implements PlatformTokenProvider { + authContext?: TokenProviderAuthContextOptions; + url: string; + userId?: string; + cachedAccessToken?: string; + cachedTokenExpiresAt?: number; + constructor(options: TokenProviderOptions); + readonly cacheIsStale: boolean; + fetchToken(tokenParams?: any): Promise; + clearToken(token?: string): void; + makeAuthRequest(): Promise; + private cache(accessToken, expiresIn); + private unixTimeNow(); +} diff --git a/dist/worker/declarations/user.d.ts b/dist/worker/declarations/user.d.ts new file mode 100644 index 0000000..7e0b5f4 --- /dev/null +++ b/dist/worker/declarations/user.d.ts @@ -0,0 +1,23 @@ +import PresencePayload from './presence_payload'; +import PresenceState from './presence_state'; +export interface UserOptions { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; +} +export default class User { + id: string; + createdAt: string; + updatedAt: string; + name: string; + avatarURL: string; + customData: any; + presenceState: PresenceState; + lastSeenAt?: string; + constructor(options: UserOptions); + updateWithPropertiesOfUser(user: User): this; + updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; +} diff --git a/dist/worker/declarations/user_store_core.d.ts b/dist/worker/declarations/user_store_core.d.ts new file mode 100644 index 0000000..a55ef61 --- /dev/null +++ b/dist/worker/declarations/user_store_core.d.ts @@ -0,0 +1,8 @@ +import User from './user'; +export default class UserStoreCore { + private users; + constructor(users?: User[]); + addOrMerge(user: User): User; + remove(id: string): User | undefined; + find(id: string): User | undefined; +} diff --git a/dist/worker/declarations/user_subscription.d.ts b/dist/worker/declarations/user_subscription.d.ts new file mode 100644 index 0000000..42ea461 --- /dev/null +++ b/dist/worker/declarations/user_subscription.d.ts @@ -0,0 +1,38 @@ +import { Instance, SubscriptionEvent } from 'pusher-platform'; +import ChatManagerDelegate from './chat_manager_delegate'; +import CurrentUser from './current_user'; +import GlobalUserStore from './global_user_store'; +import Room from './room'; +export interface UserSubscriptionOptions { + apiInstance: Instance; + filesInstance: Instance; + cursorsInstance: Instance; + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; +} +export default class UserSubscription { + userStore: GlobalUserStore; + delegate?: ChatManagerDelegate; + connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; + currentUser?: CurrentUser; + private apiInstance; + private filesInstance; + private cursorsInstance; + private typingTimers; + constructor(options: UserSubscriptionOptions); + handleEvent(event: SubscriptionEvent): void; + callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; + parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; + fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; + reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; + parseAddedToRoomPayload(eventName: string, data: any): void; + parseRemovedFromRoomPayload(eventName: string, data: any): void; + parseRoomUpdatedPayload(eventName: string, data: any): void; + parseRoomDeletedPayload(eventName: string, data: any): void; + parseUserJoinedPayload(eventName: string, data: any): void; + parseUserLeftPayload(eventName: string, data: any): void; + parseIsTypingPayload(eventName: string, data: any, userId: string): void; + private startedTyping(roomId, userId); + private stoppedTyping(roomId, userId); +} diff --git a/dist/worker/declarations/utils.d.ts b/dist/worker/declarations/utils.d.ts new file mode 100644 index 0000000..dbf28ce --- /dev/null +++ b/dist/worker/declarations/utils.d.ts @@ -0,0 +1,5 @@ +export declare function urlEncode(data: any): string; +export declare function queryString(data: any): string; +export declare function queryParamsFromFullUrl(url: string): any; +export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; +export declare function allPromisesSettled(promises: Array>): Promise; From d8797e3f1301a71d1b77739ec5d9dddb17f79b9b Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Feb 2018 16:42:36 +0000 Subject: [PATCH 41/99] clean dist --- dist/react-native/chatkit.js | 4015 ----------------- .../react-native/declarations/attachment.d.ts | 6 - .../declarations/basic_cursor.d.ts | 8 - .../declarations/basic_message.d.ts | 11 - .../declarations/basic_message_enricher.d.ts | 38 - .../react-native/declarations/basic_user.d.ts | 6 - .../declarations/chat_manager.d.ts | 25 - .../declarations/chat_manager_delegate.d.ts | 16 - dist/react-native/declarations/constants.d.ts | 2 - .../declarations/current_user.d.ts | 111 - dist/react-native/declarations/cursor.d.ts | 10 - .../declarations/cursor_subscription.d.ts | 23 - .../declarations/cursor_types.d.ts | 4 - .../declarations/fetched_attachment.d.ts | 11 - .../declarations/global_user_store.d.ts | 22 - dist/react-native/declarations/index.d.ts | 10 - dist/react-native/declarations/message.d.ts | 13 - .../declarations/payload_deserializer.d.ts | 22 - .../declarations/presence_payload.d.ts | 7 - .../declarations/presence_state.d.ts | 4 - .../declarations/presence_subscription.d.ts | 22 - dist/react-native/declarations/room.d.ts | 28 - .../declarations/room_delegate.d.ts | 16 - .../react-native/declarations/room_store.d.ts | 16 - .../declarations/room_subscription.d.ts | 15 - .../declarations/room_user_store.d.ts | 8 - .../declarations/token_provider.d.ts | 29 - dist/react-native/declarations/user.d.ts | 23 - .../declarations/user_store_core.d.ts | 8 - .../declarations/user_subscription.d.ts | 38 - dist/react-native/declarations/utils.d.ts | 5 - dist/web/declarations/attachment.d.ts | 6 - dist/web/declarations/basic_cursor.d.ts | 8 - dist/web/declarations/basic_message.d.ts | 11 - .../declarations/basic_message_enricher.d.ts | 38 - dist/web/declarations/basic_user.d.ts | 6 - dist/web/declarations/chat_manager.d.ts | 25 - .../declarations/chat_manager_delegate.d.ts | 16 - dist/web/declarations/constants.d.ts | 2 - dist/web/declarations/current_user.d.ts | 111 - dist/web/declarations/cursor.d.ts | 10 - .../web/declarations/cursor_subscription.d.ts | 23 - dist/web/declarations/cursor_types.d.ts | 4 - dist/web/declarations/fetched_attachment.d.ts | 11 - dist/web/declarations/global_user_store.d.ts | 22 - dist/web/declarations/index.d.ts | 10 - dist/web/declarations/message.d.ts | 13 - .../declarations/payload_deserializer.d.ts | 22 - dist/web/declarations/presence_payload.d.ts | 7 - dist/web/declarations/presence_state.d.ts | 4 - .../declarations/presence_subscription.d.ts | 22 - dist/web/declarations/room.d.ts | 28 - dist/web/declarations/room_delegate.d.ts | 16 - dist/web/declarations/room_store.d.ts | 16 - dist/web/declarations/room_subscription.d.ts | 15 - dist/web/declarations/room_user_store.d.ts | 8 - dist/web/declarations/token_provider.d.ts | 29 - dist/web/declarations/user.d.ts | 23 - dist/web/declarations/user_store_core.d.ts | 8 - dist/web/declarations/user_subscription.d.ts | 38 - dist/web/declarations/utils.d.ts | 5 - dist/worker/chatkit.worker.js | 3982 ---------------- dist/worker/declarations/attachment.d.ts | 6 - dist/worker/declarations/basic_cursor.d.ts | 8 - dist/worker/declarations/basic_message.d.ts | 11 - .../declarations/basic_message_enricher.d.ts | 38 - dist/worker/declarations/basic_user.d.ts | 6 - dist/worker/declarations/chat_manager.d.ts | 25 - .../declarations/chat_manager_delegate.d.ts | 16 - dist/worker/declarations/constants.d.ts | 2 - dist/worker/declarations/current_user.d.ts | 111 - dist/worker/declarations/cursor.d.ts | 10 - .../declarations/cursor_subscription.d.ts | 23 - dist/worker/declarations/cursor_types.d.ts | 4 - .../declarations/fetched_attachment.d.ts | 11 - .../declarations/global_user_store.d.ts | 22 - dist/worker/declarations/index.d.ts | 10 - dist/worker/declarations/message.d.ts | 13 - .../declarations/payload_deserializer.d.ts | 22 - .../worker/declarations/presence_payload.d.ts | 7 - dist/worker/declarations/presence_state.d.ts | 4 - .../declarations/presence_subscription.d.ts | 22 - dist/worker/declarations/room.d.ts | 28 - dist/worker/declarations/room_delegate.d.ts | 16 - dist/worker/declarations/room_store.d.ts | 16 - .../declarations/room_subscription.d.ts | 15 - dist/worker/declarations/room_user_store.d.ts | 8 - dist/worker/declarations/token_provider.d.ts | 29 - dist/worker/declarations/user.d.ts | 23 - dist/worker/declarations/user_store_core.d.ts | 8 - .../declarations/user_subscription.d.ts | 38 - dist/worker/declarations/utils.d.ts | 5 - 92 files changed, 9668 deletions(-) delete mode 100644 dist/react-native/chatkit.js delete mode 100644 dist/react-native/declarations/attachment.d.ts delete mode 100644 dist/react-native/declarations/basic_cursor.d.ts delete mode 100644 dist/react-native/declarations/basic_message.d.ts delete mode 100644 dist/react-native/declarations/basic_message_enricher.d.ts delete mode 100644 dist/react-native/declarations/basic_user.d.ts delete mode 100644 dist/react-native/declarations/chat_manager.d.ts delete mode 100644 dist/react-native/declarations/chat_manager_delegate.d.ts delete mode 100644 dist/react-native/declarations/constants.d.ts delete mode 100644 dist/react-native/declarations/current_user.d.ts delete mode 100644 dist/react-native/declarations/cursor.d.ts delete mode 100644 dist/react-native/declarations/cursor_subscription.d.ts delete mode 100644 dist/react-native/declarations/cursor_types.d.ts delete mode 100644 dist/react-native/declarations/fetched_attachment.d.ts delete mode 100644 dist/react-native/declarations/global_user_store.d.ts delete mode 100644 dist/react-native/declarations/index.d.ts delete mode 100644 dist/react-native/declarations/message.d.ts delete mode 100644 dist/react-native/declarations/payload_deserializer.d.ts delete mode 100644 dist/react-native/declarations/presence_payload.d.ts delete mode 100644 dist/react-native/declarations/presence_state.d.ts delete mode 100644 dist/react-native/declarations/presence_subscription.d.ts delete mode 100644 dist/react-native/declarations/room.d.ts delete mode 100644 dist/react-native/declarations/room_delegate.d.ts delete mode 100644 dist/react-native/declarations/room_store.d.ts delete mode 100644 dist/react-native/declarations/room_subscription.d.ts delete mode 100644 dist/react-native/declarations/room_user_store.d.ts delete mode 100644 dist/react-native/declarations/token_provider.d.ts delete mode 100644 dist/react-native/declarations/user.d.ts delete mode 100644 dist/react-native/declarations/user_store_core.d.ts delete mode 100644 dist/react-native/declarations/user_subscription.d.ts delete mode 100644 dist/react-native/declarations/utils.d.ts delete mode 100644 dist/web/declarations/attachment.d.ts delete mode 100644 dist/web/declarations/basic_cursor.d.ts delete mode 100644 dist/web/declarations/basic_message.d.ts delete mode 100644 dist/web/declarations/basic_message_enricher.d.ts delete mode 100644 dist/web/declarations/basic_user.d.ts delete mode 100644 dist/web/declarations/chat_manager.d.ts delete mode 100644 dist/web/declarations/chat_manager_delegate.d.ts delete mode 100644 dist/web/declarations/constants.d.ts delete mode 100644 dist/web/declarations/current_user.d.ts delete mode 100644 dist/web/declarations/cursor.d.ts delete mode 100644 dist/web/declarations/cursor_subscription.d.ts delete mode 100644 dist/web/declarations/cursor_types.d.ts delete mode 100644 dist/web/declarations/fetched_attachment.d.ts delete mode 100644 dist/web/declarations/global_user_store.d.ts delete mode 100644 dist/web/declarations/index.d.ts delete mode 100644 dist/web/declarations/message.d.ts delete mode 100644 dist/web/declarations/payload_deserializer.d.ts delete mode 100644 dist/web/declarations/presence_payload.d.ts delete mode 100644 dist/web/declarations/presence_state.d.ts delete mode 100644 dist/web/declarations/presence_subscription.d.ts delete mode 100644 dist/web/declarations/room.d.ts delete mode 100644 dist/web/declarations/room_delegate.d.ts delete mode 100644 dist/web/declarations/room_store.d.ts delete mode 100644 dist/web/declarations/room_subscription.d.ts delete mode 100644 dist/web/declarations/room_user_store.d.ts delete mode 100644 dist/web/declarations/token_provider.d.ts delete mode 100644 dist/web/declarations/user.d.ts delete mode 100644 dist/web/declarations/user_store_core.d.ts delete mode 100644 dist/web/declarations/user_subscription.d.ts delete mode 100644 dist/web/declarations/utils.d.ts delete mode 100644 dist/worker/chatkit.worker.js delete mode 100644 dist/worker/declarations/attachment.d.ts delete mode 100644 dist/worker/declarations/basic_cursor.d.ts delete mode 100644 dist/worker/declarations/basic_message.d.ts delete mode 100644 dist/worker/declarations/basic_message_enricher.d.ts delete mode 100644 dist/worker/declarations/basic_user.d.ts delete mode 100644 dist/worker/declarations/chat_manager.d.ts delete mode 100644 dist/worker/declarations/chat_manager_delegate.d.ts delete mode 100644 dist/worker/declarations/constants.d.ts delete mode 100644 dist/worker/declarations/current_user.d.ts delete mode 100644 dist/worker/declarations/cursor.d.ts delete mode 100644 dist/worker/declarations/cursor_subscription.d.ts delete mode 100644 dist/worker/declarations/cursor_types.d.ts delete mode 100644 dist/worker/declarations/fetched_attachment.d.ts delete mode 100644 dist/worker/declarations/global_user_store.d.ts delete mode 100644 dist/worker/declarations/index.d.ts delete mode 100644 dist/worker/declarations/message.d.ts delete mode 100644 dist/worker/declarations/payload_deserializer.d.ts delete mode 100644 dist/worker/declarations/presence_payload.d.ts delete mode 100644 dist/worker/declarations/presence_state.d.ts delete mode 100644 dist/worker/declarations/presence_subscription.d.ts delete mode 100644 dist/worker/declarations/room.d.ts delete mode 100644 dist/worker/declarations/room_delegate.d.ts delete mode 100644 dist/worker/declarations/room_store.d.ts delete mode 100644 dist/worker/declarations/room_subscription.d.ts delete mode 100644 dist/worker/declarations/room_user_store.d.ts delete mode 100644 dist/worker/declarations/token_provider.d.ts delete mode 100644 dist/worker/declarations/user.d.ts delete mode 100644 dist/worker/declarations/user_store_core.d.ts delete mode 100644 dist/worker/declarations/user_subscription.d.ts delete mode 100644 dist/worker/declarations/utils.d.ts diff --git a/dist/react-native/chatkit.js b/dist/react-native/chatkit.js deleted file mode 100644 index fa6a4dc..0000000 --- a/dist/react-native/chatkit.js +++ /dev/null @@ -1,4015 +0,0 @@ -module.exports = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 7); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var current_user_1 = __webpack_require__(11); -var presence_state_1 = __webpack_require__(4); -var room_1 = __webpack_require__(18); -var user_1 = __webpack_require__(20); -var utils_1 = __webpack_require__(1); -var checkPresenceAndTypeOfFieldsInPayload = function (requiredFieldsWithTypes, payload) { - Object.keys(requiredFieldsWithTypes).forEach(function (key) { - if (payload[key] === undefined) { - throw new Error("Payload missing key: " + key); - } - var receivedType = typeof payload[key]; - var expectedType = requiredFieldsWithTypes[key]; - if (receivedType !== expectedType) { - throw new Error("Value for key: " + key + " in payload was " + receivedType + ", expected " + expectedType); - } - }); -}; -var PayloadDeserializer = (function () { - function PayloadDeserializer() { - } - PayloadDeserializer.createUserFromPayload = function (userPayload) { - var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); - return new user_1.default({ - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - customData: userPayload.custom_data, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - }); - }; - PayloadDeserializer.createCurrentUserFromPayload = function (userPayload, apiInstance, filesInstance, cursorsInstance, userStore) { - var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); - return new current_user_1.default({ - apiInstance: apiInstance, - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - cursorsInstance: cursorsInstance, - customData: userPayload.custom_data, - filesInstance: filesInstance, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - userStore: userStore, - }); - }; - PayloadDeserializer.createRoomFromPayload = function (roomPayload) { - var requiredFieldsWithTypes = { - created_at: 'string', - created_by_id: 'string', - id: 'number', - name: 'string', - private: 'boolean', - updated_at: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, roomPayload); - var memberUserIds = []; - if (roomPayload.member_user_ids) { - memberUserIds = roomPayload.member_user_ids; - } - return new room_1.default({ - createdAt: roomPayload.created_at, - createdByUserId: roomPayload.created_by_id, - deletedAt: roomPayload.deleted_at, - id: roomPayload.id, - isPrivate: roomPayload.private, - name: roomPayload.name, - updatedAt: roomPayload.updated_at, - userIds: memberUserIds, - }); - }; - PayloadDeserializer.createBasicMessageFromPayload = function (messagePayload) { - var requiredFieldsWithTypes = { - created_at: 'string', - id: 'number', - room_id: 'number', - text: 'string', - updated_at: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, messagePayload); - var attachment = this.createAttachmentFromPayload(messagePayload.attachment); - return { - attachment: attachment, - createdAt: messagePayload.created_at, - id: messagePayload.id, - roomId: messagePayload.room_id, - senderId: messagePayload.user_id, - text: messagePayload.text, - updatedAt: messagePayload.updated_at, - }; - }; - PayloadDeserializer.createBasicCursorFromPayload = function (payload) { - var requiredFieldsWithTypes = { - cursor_type: 'number', - position: 'number', - room_id: 'number', - updated_at: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - return { - cursorType: payload.cursor_type, - position: payload.position, - roomId: payload.room_id, - updatedAt: payload.updated_at, - userId: payload.user_id, - }; - }; - PayloadDeserializer.createPresencePayloadFromPayload = function (payload) { - var requiredFieldsWithTypes = { - state: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var state = new presence_state_1.default(payload.state); - return { - lastSeenAt: payload.last_seen_at, - state: state, - userId: payload.user_id, - }; - }; - PayloadDeserializer.createBasicUserFromPayload = function (payload) { - var requiredFieldsWithTypes = { - created_at: 'string', - id: 'string', - updated_at: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - return { - createdAt: payload.created_at, - id: payload.id, - updatedAt: payload.updated_at, - }; - }; - PayloadDeserializer.createAttachmentFromPayload = function (payload) { - if (payload === undefined) { - return undefined; - } - var requiredFieldsWithTypes = { - resource_link: 'string', - type: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var linkQueryParams = utils_1.queryParamsFromFullUrl(payload.resource_link); - var fetchRequired = linkQueryParams.chatkit_link !== undefined && - linkQueryParams.chatkit_link === 'true'; - return { - fetchRequired: fetchRequired, - link: payload.resource_link, - type: payload.type, - }; - }; - PayloadDeserializer.createFetchedAttachmentFromPayload = function (payload) { - if (payload === undefined) { - return undefined; - } - var requiredFieldsWithTypes = { - file: 'object', - resource_link: 'string', - ttl: 'number', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var requiredFieldsWithTypesForFileField = { - bytes: 'number', - last_modified: 'number', - name: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypesForFileField, payload.file); - var file = payload.file; - var bytes = file.bytes, name = file.name; - return { - file: { - bytes: bytes, - lastModified: file.last_modified, - name: name, - }, - link: payload.resource_link, - ttl: payload.ttl, - }; - }; - return PayloadDeserializer; -}()); -exports.default = PayloadDeserializer; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function urlEncode(data) { - return Object.keys(data) - .filter(function (key) { return data[key] !== undefined; }) - .map(function (key) { return key + "=" + encodeURIComponent(data[key]); }) - .join('&'); -} -exports.urlEncode = urlEncode; -function queryString(data) { - var encodedData = urlEncode(data); - return encodedData ? "?" + encodedData : ''; -} -exports.queryString = queryString; -function queryParamsFromFullUrl(url) { - if (url.indexOf('?') === -1) { - return {}; - } - var splitUrl = url.split('?'); - var queryStr = splitUrl.slice(1).join('&'); - return queryParamObject(queryStr); -} -exports.queryParamsFromFullUrl = queryParamsFromFullUrl; -function querylessUrlAndQueryObjectFromFullUrl(urlString) { - if (urlString.indexOf('?') === -1) { - return { - queryObject: {}, - querylessUrl: urlString, - }; - } - var splitUrl = urlString.split('?'); - var querylessUrl = splitUrl[0]; - var queryStr = splitUrl.slice(1).join('&'); - return { - queryObject: queryParamObject(queryStr), - querylessUrl: querylessUrl, - }; -} -function queryParamObject(queryParamString) { - return queryParamString - .split('&') - .map(function (str) { - var _a = str.split('='), key = _a[0], value = _a[1]; - return _b = {}, _b[key] = decodeURI(value), _b; - var _b; - }) - .reduce(function (prev, curr) { return Object.assign(prev, curr); }); -} -function mergeQueryParamsIntoUrl(urlString, queryParams) { - var _a = querylessUrlAndQueryObjectFromFullUrl(urlString), querylessUrl = _a.querylessUrl, queryObject = _a.queryObject; - var fullQueryString = queryString(Object.assign(queryObject, queryParams)); - return "" + querylessUrl + fullQueryString; -} -exports.mergeQueryParamsIntoUrl = mergeQueryParamsIntoUrl; -function allPromisesSettled(promises) { - return Promise.all(promises.map(function (p) { - return Promise.resolve(p).then(function (v) { return ({ - state: 'fulfilled', - value: v, - }); }, function (r) { return ({ - reason: r, - state: 'rejected', - }); }); - })); -} -exports.allPromisesSettled = allPromisesSettled; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(8); - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.TYPING_REQ_TTL = 1500; -exports.TYPING_REQ_LEEWAY = 500; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var PresenceState = (function () { - function PresenceState(state) { - switch (state) { - case 'online': - this.stringValue = state; - break; - case 'offline': - this.stringValue = state; - break; - default: - this.stringValue = 'unknown'; - break; - } - } - return PresenceState; -}()); -exports.default = PresenceState; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var UserStoreCore = (function () { - function UserStoreCore(users) { - if (users === void 0) { users = new Array(); } - this.users = users; - } - UserStoreCore.prototype.addOrMerge = function (user) { - var existingUser = this.users.find(function (el) { return el.id === user.id; }); - if (existingUser) { - existingUser.updateWithPropertiesOfUser(user); - return existingUser; - } - else { - this.users.push(user); - return user; - } - }; - UserStoreCore.prototype.remove = function (id) { - var indexOfUser = this.users.findIndex(function (el) { return el.id === id; }); - if (indexOfUser === -1) { - return undefined; - } - var user = this.users[indexOfUser]; - this.users.splice(indexOfUser, 1); - return user; - }; - UserStoreCore.prototype.find = function (id) { - return this.users.find(function (el) { return el.id === id; }); - }; - return UserStoreCore; -}()); -exports.default = UserStoreCore; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var utils_1 = __webpack_require__(1); -var TokenProvider = (function () { - function TokenProvider(options) { - this.authContext = options.authContext || {}; - this.url = options.url; - } - Object.defineProperty(TokenProvider.prototype, "cacheIsStale", { - get: function () { - if (this.cachedAccessToken && this.cachedTokenExpiresAt) { - return this.unixTimeNow() > this.cachedTokenExpiresAt; - } - return true; - }, - enumerable: true, - configurable: true - }); - TokenProvider.prototype.fetchToken = function (tokenParams) { - var _this = this; - if (this.cacheIsStale) { - return this.makeAuthRequest().then(function (responseBody) { - var access_token = responseBody.access_token, expires_in = responseBody.expires_in; - _this.cache(access_token, expires_in); - return access_token; - }); - } - return new Promise(function (resolve, reject) { - resolve(_this.cachedAccessToken); - }); - }; - TokenProvider.prototype.clearToken = function (token) { - this.cachedAccessToken = undefined; - this.cachedTokenExpiresAt = undefined; - }; - TokenProvider.prototype.makeAuthRequest = function () { - var url; - var authRequestQueryParams = (this.authContext || {}).queryParams || {}; - if (this.userId === undefined) { - url = utils_1.mergeQueryParamsIntoUrl(this.url, authRequestQueryParams); - } - else { - var authContextWithUserId = __assign({ user_id: this.userId }, authRequestQueryParams); - url = utils_1.mergeQueryParamsIntoUrl(this.url, authContextWithUserId); - } - var authRequestHeaders = (this.authContext || {}).headers || {}; - var headers = __assign((_a = {}, _a['Content-Type'] = 'application/x-www-form-urlencoded', _a), authRequestHeaders); - var body = utils_1.urlEncode({ grant_type: 'client_credentials' }); - return pusher_platform_1.sendRawRequest({ - body: body, - headers: headers, - method: 'POST', - url: url, - }).then(function (res) { - return JSON.parse(res); - }); - var _a; - }; - TokenProvider.prototype.cache = function (accessToken, expiresIn) { - this.cachedAccessToken = accessToken; - this.cachedTokenExpiresAt = this.unixTimeNow() + expiresIn; - }; - TokenProvider.prototype.unixTimeNow = function () { - return Math.floor(Date.now() / 1000); - }; - return TokenProvider; -}()); -exports.default = TokenProvider; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -exports.BaseClient = pusher_platform_1.BaseClient; -var chat_manager_1 = __webpack_require__(9); -exports.ChatManager = chat_manager_1.default; -var token_provider_1 = __webpack_require__(6); -exports.TokenProvider = token_provider_1.default; -exports.default = { - BaseClient: pusher_platform_1.BaseClient, - ChatManager: chat_manager_1.default, - TokenProvider: token_provider_1.default, -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -module.exports = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 11); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function responseToHeadersObject(headerStr) { - var headers = {}; - if (!headerStr) { - return headers; - } - var headerPairs = headerStr.split('\u000d\u000a'); - for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { - var headerPair = headerPairs_1[_i]; - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - return headers; -} -exports.responseToHeadersObject = responseToHeadersObject; -var ErrorResponse = (function () { - function ErrorResponse(statusCode, headers, info) { - this.statusCode = statusCode; - this.headers = headers; - this.info = info; - } - ErrorResponse.fromXHR = function (xhr) { - var errorInfo = xhr.responseText; - try { - errorInfo = JSON.parse(xhr.responseText); - } - catch (e) { - } - return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); - }; - return ErrorResponse; -}()); -exports.ErrorResponse = ErrorResponse; -var NetworkError = (function () { - function NetworkError(error) { - this.error = error; - } - return NetworkError; -}()); -exports.NetworkError = NetworkError; -var XhrReadyState; -(function (XhrReadyState) { - XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; - XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; - XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; - XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; - XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; -})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -Object.defineProperty(exports, "__esModule", { value: true }); -var LogLevel; -(function (LogLevel) { - LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; - LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; - LogLevel[LogLevel["INFO"] = 3] = "INFO"; - LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; - LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; -})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); -var ConsoleLogger = (function () { - function ConsoleLogger(threshold) { - if (threshold === void 0) { threshold = 2; } - this.threshold = threshold; - var groups = Array(); - var hr = '--------------------------------------------------------------------------------'; - if (!global.console.group) { - global.console.group = function (label) { - groups.push(label); - global.console.log('%c \nBEGIN GROUP: %c', hr, label); - }; - } - if (!global.console.groupEnd) { - global.console.groupEnd = function () { - global.console.log('END GROUP: %c\n%c', groups.pop(), hr); - }; - } - } - ConsoleLogger.prototype.verbose = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(global.console.log, LogLevel.VERBOSE, items); - }; - ConsoleLogger.prototype.debug = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(global.console.log, LogLevel.DEBUG, items); - }; - ConsoleLogger.prototype.info = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(global.console.info, LogLevel.INFO, items); - }; - ConsoleLogger.prototype.warn = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(global.console.warn, LogLevel.WARNING, items); - }; - ConsoleLogger.prototype.error = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(global.console.error, LogLevel.ERROR, items); - }; - ConsoleLogger.prototype.log = function (logFunction, level, items) { - var _this = this; - if (level >= this.threshold) { - var loggerSignature_1 = "Logger." + LogLevel[level]; - if (items.length > 1) { - global.console.group(); - items.forEach(function (item) { - _this.errorAwareLog(logFunction, item, loggerSignature_1); - }); - global.console.groupEnd(); - } - else { - this.errorAwareLog(logFunction, items[0], loggerSignature_1); - } - } - }; - ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { - if (item.info && item.info.error_uri) { - var errorDesc = item.info.error_description; - var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; - logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); - } - else { - logFunction(loggerSignature + ": ", item); - } - }; - return ConsoleLogger; -}()); -exports.ConsoleLogger = ConsoleLogger; -var EmptyLogger = (function () { - function EmptyLogger() { - } - EmptyLogger.prototype.verbose = function (message, error) { }; - EmptyLogger.prototype.debug = function (message, error) { }; - EmptyLogger.prototype.info = function (message, error) { }; - EmptyLogger.prototype.warn = function (message, error) { }; - EmptyLogger.prototype.error = function (message, error) { }; - return EmptyLogger; -}()); -exports.EmptyLogger = EmptyLogger; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createRetryStrategyOptionsOrDefault = function (options) { - var initialTimeoutMillis = options.initialTimeoutMillis || 1000; - var maxTimeoutMillis = options.maxTimeoutMillis || 5000; - var limit = -1; - if (options.limit !== undefined && options.limit != null) { - limit = options.limit; - } - var increaseTimeout; - if (options.increaseTimeout !== undefined) { - increaseTimeout = options.increaseTimeout; - } - else { - increaseTimeout = function (currentTimeout) { - if (currentTimeout * 2 > maxTimeoutMillis) { - return maxTimeoutMillis; - } - else { - return currentTimeout * 2; - } - }; - } - return { - increaseTimeout: increaseTimeout, - initialTimeoutMillis: initialTimeoutMillis, - limit: limit, - maxTimeoutMillis: maxTimeoutMillis, - }; -}; -var Retry = (function () { - function Retry(waitTimeMillis) { - this.waitTimeMillis = waitTimeMillis; - } - return Retry; -}()); -exports.Retry = Retry; -var DoNotRetry = (function () { - function DoNotRetry(error) { - this.error = error; - } - return DoNotRetry; -}()); -exports.DoNotRetry = DoNotRetry; -var requestMethodIsSafe = function (method) { - method = method.toUpperCase(); - return (method === 'GET' || - method === 'HEAD' || - method === 'OPTIONS' || - method === 'SUBSCRIBE'); -}; -var RetryResolution = (function () { - function RetryResolution(options, logger, retryUnsafeRequests) { - this.options = options; - this.logger = logger; - this.retryUnsafeRequests = retryUnsafeRequests; - this.currentRetryCount = 0; - this.initialTimeoutMillis = options.initialTimeoutMillis; - this.maxTimeoutMillis = options.maxTimeoutMillis; - this.limit = options.limit; - this.increaseTimeoutFunction = options.increaseTimeout; - this.currentBackoffMillis = this.initialTimeoutMillis; - } - RetryResolution.prototype.attemptRetry = function (error) { - this.logger.verbose(this.constructor.name + ": Error received", error); - if (this.currentRetryCount >= this.limit && this.limit >= 0) { - this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); - return new DoNotRetry(error); - } - if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { - this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); - return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); - } - if (error instanceof network_1.NetworkError || - (error instanceof network_1.ErrorResponse && - requestMethodIsSafe(error.headers['Request-Method'])) || - this.retryUnsafeRequests) { - return this.shouldSafeRetry(error); - } - if (error instanceof network_1.NetworkError) { - return this.shouldSafeRetry(error); - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.shouldSafeRetry = function (error) { - if (error instanceof network_1.NetworkError) { - this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); - return new Retry(this.calulateMillisToRetry()); - } - else if (error instanceof network_1.ErrorResponse) { - if (error.statusCode >= 500 && error.statusCode < 600) { - this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); - return new Retry(this.calulateMillisToRetry()); - } - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.calulateMillisToRetry = function () { - this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); - this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); - return this.currentBackoffMillis; - }; - return RetryResolution; -}()); -exports.RetryResolution = RetryResolution; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var logger_1 = __webpack_require__(2); -var request_1 = __webpack_require__(5); -var resuming_subscription_1 = __webpack_require__(6); -var retrying_subscription_1 = __webpack_require__(7); -var subscribe_strategy_1 = __webpack_require__(12); -var subscription_1 = __webpack_require__(13); -var token_providing_subscription_1 = __webpack_require__(8); -var http_1 = __webpack_require__(14); -var websocket_1 = __webpack_require__(15); -var transports_1 = __webpack_require__(9); -var BaseClient = (function () { - function BaseClient(options) { - this.options = options; - this.host = options.host.replace(/(\/)+$/, ''); - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.websocketTransport = new websocket_1.default(this.host); - this.httpTransport = new http_1.default(this.host, options.encrypted); - } - BaseClient.prototype.request = function (options, tokenParams) { - var _this = this; - if (options.tokenProvider) { - return options.tokenProvider - .fetchToken(tokenParams) - .then(function (token) { - if (options.headers !== undefined) { - options.headers['Authorization'] = "Bearer " + token; - } - else { - options.headers = (_a = {}, - _a['Authorization'] = "Bearer " + token, - _a); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - var _a; - }) - .catch(function (error) { - _this.logger.error(error); - }); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - }; - BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - return BaseClient; -}()); -exports.BaseClient = BaseClient; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -function executeNetworkRequest(createXhr, options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); - sendBody(xhr, options); - }); -} -exports.executeNetworkRequest = executeNetworkRequest; -function sendBody(xhr, options) { - if (options.json) { - xhr.send(JSON.stringify(options.json)); - } - else { - xhr.send(options.body); - } -} -function sendRawRequest(options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(new global.XMLHttpRequest(), resolve, reject); - xhr.open(options.method.toUpperCase(), options.url, true); - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - xhr.send(options.body); - }); -} -exports.sendRawRequest = sendRawRequest; -function attachOnReadyStateChangeHandler(xhr, resolve, reject) { - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status >= 200 && xhr.status < 300) { - resolve(xhr.response); - } - else if (xhr.status !== 0) { - reject(network_1.ErrorResponse.fromXHR(xhr)); - } - else { - reject(new network_1.NetworkError('No Connection')); - } - } - }; - return xhr; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(3); -exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { - var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); - var ResumingSubscription = (function () { - function ResumingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - this.onTransition = onTransition; - var lastEventId = initialEventId; - logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); - if (lastEventId) { - headers['Last-Event-Id'] = lastEventId; - logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); - } - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpeningSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpenSubscriptionState; - }()); - var ResumingSubscriptionState = (function () { - function ResumingSubscriptionState(error, onTransition, lastEventId) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); - var executeSubscriptionOnce = function (error, lastEventId) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = global.setTimeout(function () { - executeNextSubscribeStrategy(lastEventId); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function (lastEventId) { - logger.verbose("ResumingSubscription: trying to re-establish the subscription"); - if (lastEventId) { - logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); - headers['Last-Event-Id'] = lastEventId; - } - _this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - executeSubscriptionOnce(error, lastEventId); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error, lastEventId); - } - ResumingSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - global.clearTimeout(this.timeout); - this.underlyingSubscription.unsubscribe(); - }; - return ResumingSubscriptionState; - }()); - var EndingSubscriptionState = (function () { - function EndingSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); - } - EndingSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription is already ending'); - }; - return EndingSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return ResumingSubscription; - }()); - return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(3); -exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { - var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); - var RetryingSubscription = (function () { - function RetryingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { - return onTransition(new RetryingSubscriptionState(error, onTransition)); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - throw new Error('Method not implemented.'); - }; - return OpeningSubscriptionState; - }()); - var RetryingSubscriptionState = (function () { - function RetryingSubscriptionState(error, onTransition) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); - var executeSubscriptionOnce = function (error) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = global.setTimeout(function () { - executeNextSubscribeStrategy(); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function () { - logger.verbose("RetryingSubscription: trying to re-establish the subscription"); - var underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { return executeSubscriptionOnce(error); }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error); - } - RetryingSubscriptionState.prototype.unsubscribe = function () { - global.clearTimeout(this.timeout); - this.onTransition(new EndedSubscriptionState()); - }; - return RetryingSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - this.onTransition(new EndedSubscriptionState()); - }; - return OpenSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return RetryingSubscription; - }()); - return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { - if (tokenProvider) { - return function (listeners, headers) { - return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); - }; - } - return nextSubscribeStrategy; -}; -var TokenProvidingSubscription = (function () { - function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { - var _this = this; - this.logger = logger; - this.listeners = listeners; - this.headers = headers; - this.tokenProvider = tokenProvider; - this.nextSubscribeStrategy = nextSubscribeStrategy; - this.unsubscribe = function () { - _this.state.unsubscribe(); - _this.state = new InactiveState(_this.logger); - }; - this.state = new ActiveState(logger, headers, nextSubscribeStrategy); - this.subscribe(); - } - TokenProvidingSubscription.prototype.subscribe = function () { - var _this = this; - this.tokenProvider - .fetchToken() - .then(function (token) { - var existingListeners = Object.assign({}, _this.listeners); - _this.state.subscribe(token, { - onEnd: function (error) { - _this.state = new InactiveState(_this.logger); - existingListeners.onEnd(error); - }, - onError: function (error) { - if (_this.isTokenExpiredError(error)) { - _this.tokenProvider.clearToken(token); - _this.subscribe(); - } - else { - _this.state = new InactiveState(_this.logger); - existingListeners.onError(error); - } - }, - onEvent: _this.listeners.onEvent, - onOpen: _this.listeners.onOpen, - }); - }) - .catch(function (error) { - _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); - _this.state = new InactiveState(_this.logger); - _this.listeners.onError(error); - }); - }; - TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { - return (error instanceof network_1.ErrorResponse && - error.statusCode === 401 && - error.info === 'authentication/expired'); - }; - return TokenProvidingSubscription; -}()); -var ActiveState = (function () { - function ActiveState(logger, headers, nextSubscribeStrategy) { - this.logger = logger; - this.headers = headers; - this.nextSubscribeStrategy = nextSubscribeStrategy; - logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); - } - ActiveState.prototype.subscribe = function (token, listeners) { - var _this = this; - this.putTokenIntoHeader(token); - this.underlyingSubscription = this.nextSubscribeStrategy({ - onEnd: function (error) { - _this.logger.verbose("TokenProvidingSubscription: subscription ended"); - listeners.onEnd(error); - }, - onError: function (error) { - _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); - listeners.onError(error); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - _this.logger.verbose("TokenProvidingSubscription: subscription opened"); - listeners.onOpen(headers); - }, - onRetrying: listeners.onRetrying, - }, this.headers); - }; - ActiveState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - }; - ActiveState.prototype.putTokenIntoHeader = function (token) { - this.headers['Authorization'] = "Bearer " + token; - this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); - }; - return ActiveState; -}()); -var InactiveState = (function () { - function InactiveState(logger) { - this.logger = logger; - logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); - } - InactiveState.prototype.subscribe = function (token, listeners) { - this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); - }; - InactiveState.prototype.unsubscribe = function () { - this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); - }; - return InactiveState; -}()); - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createTransportStrategy = function (path, transport, logger) { - return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; -}; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HOST_BASE = 'pusherplatform.io'; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(4); -exports.BaseClient = base_client_1.BaseClient; -var host_base_1 = __webpack_require__(10); -exports.HOST_BASE = host_base_1.HOST_BASE; -var instance_1 = __webpack_require__(16); -exports.Instance = instance_1.default; -var logger_1 = __webpack_require__(2); -exports.ConsoleLogger = logger_1.ConsoleLogger; -exports.EmptyLogger = logger_1.EmptyLogger; -var network_1 = __webpack_require__(0); -exports.ErrorResponse = network_1.ErrorResponse; -exports.NetworkError = network_1.NetworkError; -exports.responseToHeadersObject = network_1.responseToHeadersObject; -exports.XhrReadyState = network_1.XhrReadyState; -var request_1 = __webpack_require__(5); -exports.executeNetworkRequest = request_1.executeNetworkRequest; -exports.sendRawRequest = request_1.sendRawRequest; -var resuming_subscription_1 = __webpack_require__(6); -exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; -var retry_strategy_1 = __webpack_require__(3); -exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; -exports.DoNotRetry = retry_strategy_1.DoNotRetry; -exports.Retry = retry_strategy_1.Retry; -exports.RetryResolution = retry_strategy_1.RetryResolution; -var retrying_subscription_1 = __webpack_require__(7); -exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; -var token_providing_subscription_1 = __webpack_require__(8); -exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; -var transports_1 = __webpack_require__(9); -exports.createTransportStrategy = transports_1.createTransportStrategy; -exports.default = { - BaseClient: base_client_1.BaseClient, - ConsoleLogger: logger_1.ConsoleLogger, - EmptyLogger: logger_1.EmptyLogger, - Instance: instance_1.default, -}; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { - return { - onEnd: subListeners.onEnd, - onError: subListeners.onError, - onEvent: subListeners.onEvent, - onOpen: subListeners.onOpen, - onRetrying: subListeners.onRetrying, - }; -}; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.replaceMissingListenersWithNoOps = function (listeners) { - var onEndNoOp = function (error) { }; - var onEnd = listeners.onEnd || onEndNoOp; - var onErrorNoOp = function (error) { }; - var onError = listeners.onError || onErrorNoOp; - var onEventNoOp = function (event) { }; - var onEvent = listeners.onEvent || onEventNoOp; - var onOpenNoOp = function (headers) { }; - var onOpen = listeners.onOpen || onOpenNoOp; - var onRetryingNoOp = function () { }; - var onRetrying = listeners.onRetrying || onRetryingNoOp; - var onSubscribeNoOp = function () { }; - var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; - return { - onEnd: onEnd, - onError: onError, - onEvent: onEvent, - onOpen: onOpen, - onRetrying: onRetrying, - onSubscribe: onSubscribe, - }; -}; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var HttpTransportState; -(function (HttpTransportState) { - HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; - HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; - HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; - HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; - HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; -})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); -var HttpSubscription = (function () { - function HttpSubscription(xhr, listeners) { - var _this = this; - this.gotEOS = false; - this.lastNewlineIndex = 0; - this.state = HttpTransportState.UNOPENED; - this.xhr = xhr; - this.listeners = listeners; - this.xhr.onreadystatechange = function () { - switch (_this.xhr.readyState) { - case network_1.XhrReadyState.UNSENT: - case network_1.XhrReadyState.OPENED: - case network_1.XhrReadyState.HEADERS_RECEIVED: - _this.assertStateIsIn(HttpTransportState.OPENING); - break; - case network_1.XhrReadyState.LOADING: - _this.onLoading(); - break; - case network_1.XhrReadyState.DONE: - _this.onDone(); - break; - } - }; - this.state = HttpTransportState.OPENING; - this.xhr.send(); - return this; - } - HttpSubscription.prototype.unsubscribe = function () { - this.state = HttpTransportState.ENDED; - this.xhr.abort(); - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - }; - HttpSubscription.prototype.onLoading = function () { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - global.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN); - var err = this.onChunk(); - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - if (err) { - this.state = HttpTransportState.ENDED; - if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else { - } - } - }; - HttpSubscription.prototype.onDone = function () { - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - var err = this.onChunk(); - if (err) { - this.state = HttpTransportState.ENDED; - if (err.statusCode === 204) { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else if (this.state <= HttpTransportState.ENDING) { - if (this.listeners.onError) { - this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); - } - } - else { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - } - else { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); - if (this.state === HttpTransportState.ENDED) { - return; - } - else if (this.xhr.status === 0) { - if (this.listeners.onError) { - this.listeners.onError(new network_1.NetworkError('Connection lost.')); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); - } - } - } - }; - HttpSubscription.prototype.onChunk = function () { - this.assertStateIsIn(HttpTransportState.OPEN); - var response = this.xhr.responseText; - var newlineIndex = response.lastIndexOf('\n'); - if (newlineIndex > this.lastNewlineIndex) { - var rawEvents = response - .slice(this.lastNewlineIndex, newlineIndex) - .split('\n'); - this.lastNewlineIndex = newlineIndex; - for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { - var rawEvent = rawEvents_1[_i]; - if (rawEvent.length === 0) { - continue; - } - var data = JSON.parse(rawEvent); - var err = this.onMessage(data); - if (err != null) { - return err; - } - } - } - }; - HttpSubscription.prototype.assertStateIsIn = function () { - var _this = this; - var validStates = []; - for (var _i = 0; _i < arguments.length; _i++) { - validStates[_i] = arguments[_i]; - } - var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); - if (!stateIsValid) { - var expectedStates = validStates - .map(function (state) { return HttpTransportState[state]; }) - .join(', '); - var actualState = HttpTransportState[this.state]; - global.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); - } - }; - HttpSubscription.prototype.onMessage = function (message) { - this.assertStateIsIn(HttpTransportState.OPEN); - this.verifyMessage(message); - switch (message[0]) { - case 0: - return null; - case 1: - return this.onEventMessage(message); - case 255: - return this.onEOSMessage(message); - default: - return new Error('Unknown Message: ' + JSON.stringify(message)); - } - }; - HttpSubscription.prototype.onEventMessage = function (eventMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eventMessage.length !== 4) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; - if (typeof id !== 'string') { - return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); - } - if (this.listeners.onEvent) { - this.listeners.onEvent({ body: body, headers: headers, eventId: id }); - } - return null; - }; - HttpSubscription.prototype.onEOSMessage = function (eosMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eosMessage.length !== 4) { - return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); - } - var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; - if (typeof statusCode !== 'number') { - return new Error('Invalid EOS Status Code'); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid EOS ElementsHeaders'); - } - this.state = HttpTransportState.ENDING; - return new network_1.ErrorResponse(statusCode, headers, info); - }; - HttpSubscription.prototype.verifyMessage = function (message) { - if (this.gotEOS) { - return new Error('Got another message after EOS message'); - } - if (!Array.isArray(message)) { - return new Error('Message is not an array'); - } - if (message.length < 1) { - return new Error('Message is empty array'); - } - }; - return HttpSubscription; -}()); -var HttpTransport = (function () { - function HttpTransport(host, encrypted) { - if (encrypted === void 0) { encrypted = true; } - this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; - } - HttpTransport.prototype.request = function (requestOptions) { - return this.createXHR(this.baseURL, requestOptions); - }; - HttpTransport.prototype.subscribe = function (path, listeners, headers) { - var requestOptions = { - headers: headers, - method: 'SUBSCRIBE', - path: path, - }; - return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); - }; - HttpTransport.prototype.createXHR = function (baseURL, options) { - var xhr = new global.XMLHttpRequest(); - var path = options.path.replace(/^\/+/, ''); - var endpoint = baseURL + "/" + path; - xhr.open(options.method.toUpperCase(), endpoint, true); - xhr = this.setJSONHeaderIfAppropriate(xhr, options); - if (options.jwt) { - xhr.setRequestHeader('authorization', "Bearer " + options.jwt); - } - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - return xhr; - }; - HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { - if (options.json) { - xhr.setRequestHeader('content-type', 'application/json'); - } - return xhr; - }; - return HttpTransport; -}()); -exports.default = HttpTransport; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var SubscribeMessageType = 100; -var OpenMessageType = 101; -var EventMessageType = 102; -var UnsubscribeMessageType = 198; -var EosMessageType = 199; -var PingMessageType = 16; -var PongMessageType = 17; -var CloseMessageType = 99; -var WSReadyState; -(function (WSReadyState) { - WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; - WSReadyState[WSReadyState["Open"] = 1] = "Open"; - WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; - WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; -})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); -var WsSubscriptions = (function () { - function WsSubscriptions() { - this.subscriptions = {}; - } - WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { - this.subscriptions[subID] = { - headers: headers, - listeners: listeners, - path: path, - }; - return subID; - }; - WsSubscriptions.prototype.has = function (subID) { - return this.subscriptions[subID] !== undefined; - }; - WsSubscriptions.prototype.isEmpty = function () { - return Object.keys(this.subscriptions).length === 0; - }; - WsSubscriptions.prototype.remove = function (subID) { - return delete this.subscriptions[subID]; - }; - WsSubscriptions.prototype.get = function (subID) { - return this.subscriptions[subID]; - }; - WsSubscriptions.prototype.getAll = function () { - return this.subscriptions; - }; - WsSubscriptions.prototype.getAllAsArray = function () { - var _this = this; - return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); - }; - WsSubscriptions.prototype.removeAll = function () { - this.subscriptions = {}; - }; - return WsSubscriptions; -}()); -var WsSubscription = (function () { - function WsSubscription(wsTransport, subID) { - this.wsTransport = wsTransport; - this.subID = subID; - } - WsSubscription.prototype.unsubscribe = function () { - this.wsTransport.unsubscribe(this.subID); - }; - return WsSubscription; -}()); -var pingIntervalMs = 30000; -var pingTimeoutMs = 10000; -var WebSocketTransport = (function () { - function WebSocketTransport(host) { - this.webSocketPath = '/ws'; - this.forcedClose = false; - this.closedError = null; - this.baseURL = "wss://" + host + this.webSocketPath; - this.lastSubscriptionID = 0; - this.subscriptions = new WsSubscriptions(); - this.pendingSubscriptions = new WsSubscriptions(); - this.connect(); - } - WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { - this.tryReconnectIfNeeded(); - var subID = this.lastSubscriptionID++; - if (this.socket.readyState !== WSReadyState.Open) { - this.pendingSubscriptions.add(subID, path, listeners, headers); - return new WsSubscription(this, subID); - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - return new WsSubscription(this, subID); - }; - WebSocketTransport.prototype.unsubscribe = function (subID) { - this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); - var subscription = this.subscriptions.get(subID); - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - this.subscriptions.remove(subID); - }; - WebSocketTransport.prototype.connect = function () { - var _this = this; - this.close(); - this.forcedClose = false; - this.closedError = null; - this.socket = new global.WebSocket(this.baseURL); - this.socket.onopen = function (event) { - var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); - allPendingSubscriptions.forEach(function (subscription) { - var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; - _this.subscribePending(path, listeners, headers, subID); - }); - _this.pendingSubscriptions.removeAll(); - _this.pingInterval = global.setInterval(function () { - if (_this.pongTimeout) { - return; - } - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - return; - } - _this.sendMessage(_this.getMessage(PingMessageType, now)); - _this.lastSentPingID = now; - _this.pongTimeout = global.setTimeout(function () { - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - _this.pongTimeout = null; - return; - } - _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); - }, pingTimeoutMs); - }, pingIntervalMs); - }; - this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; - this.socket.onerror = function (event) { - _this.close(new network_1.NetworkError('Connection was lost.')); - }; - this.socket.onclose = function (event) { - if (!_this.forcedClose) { - _this.tryReconnectIfNeeded(); - return; - } - var callback = _this.closedError - ? function (subscription) { - if (subscription.listeners.onError) { - subscription.listeners.onError(_this.closedError); - } - } - : function (subscription) { - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - }; - var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false - ? _this.pendingSubscriptions - : _this.subscriptions; - allSubscriptions.getAllAsArray().forEach(callback); - allSubscriptions.removeAll(); - if (_this.closedError) { - _this.tryReconnectIfNeeded(); - } - }; - }; - WebSocketTransport.prototype.close = function (error) { - if (!(this.socket instanceof global.WebSocket)) { - return; - } - this.forcedClose = true; - this.closedError = error; - this.socket.close(); - global.clearTimeout(this.pingInterval); - global.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.tryReconnectIfNeeded = function () { - if (this.socket.readyState !== WSReadyState.Closed) { - return; - } - this.connect(); - }; - WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { - if (subID === undefined) { - global.console.logger.debug("Subscription to path " + path + " has an undefined ID"); - return; - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - }; - WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { - return [messageType, id, path, headers]; - }; - WebSocketTransport.prototype.sendMessage = function (message) { - if (this.socket.readyState !== WSReadyState.Open) { - return global.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); - } - this.socket.send(JSON.stringify(message)); - }; - WebSocketTransport.prototype.subscription = function (subID) { - return this.subscriptions.get(subID); - }; - WebSocketTransport.prototype.receiveMessage = function (event) { - this.lastMessageReceivedTimestamp = new Date().getTime(); - var message; - try { - message = JSON.parse(event.data); - } - catch (err) { - this.close(new Error("Message is not valid JSON format. Getting " + event.data)); - return; - } - var nonValidMessageError = this.validateMessage(message); - if (nonValidMessageError) { - this.close(new Error(nonValidMessageError.message)); - return; - } - var messageType = message.shift(); - switch (messageType) { - case PongMessageType: - this.onPongMessage(message); - return; - case PingMessageType: - this.onPingMessage(message); - return; - case CloseMessageType: - this.onCloseMessage(message); - return; - } - var subID = message.shift(); - var subscription = this.subscription(subID); - if (!subscription) { - this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); - return; - } - var listeners = subscription.listeners; - switch (messageType) { - case OpenMessageType: - this.onOpenMessage(message, subID, listeners); - break; - case EventMessageType: - this.onEventMessage(message, listeners); - break; - case EosMessageType: - this.onEOSMessage(message, subID, listeners); - break; - default: - this.close(new Error('Received non existing type of message.')); - } - }; - WebSocketTransport.prototype.validateMessage = function (message) { - if (!Array.isArray(message)) { - return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); - } - if (message.length < 1) { - return new Error("Message is empty array: " + JSON.stringify(message)); - } - return null; - }; - WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { - if (subscriptionListeners.onOpen) { - subscriptionListeners.onOpen(message[1]); - } - }; - WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { - if (eventMessage.length !== 3) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; - if (typeof eventId !== 'string') { - return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); - } - if (subscriptionListeners.onEvent) { - subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); - } - }; - WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { - this.subscriptions.remove(subID); - if (eosMessage.length !== 3) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); - } - return; - } - var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; - if (typeof statusCode !== 'number') { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS Status Code')); - } - return; - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); - } - return; - } - if (statusCode === 204) { - if (subscriptionListeners.onEnd) { - subscriptionListeners.onEnd(null); - } - return; - } - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); - } - return; - }; - WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { - var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; - if (typeof statusCode !== 'number') { - return this.close(new Error('Close message: Invalid EOS Status Code')); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); - } - this.close(); - }; - WebSocketTransport.prototype.onPongMessage = function (message) { - var receviedPongID = message[0]; - if (this.lastSentPingID !== receviedPongID) { - this.close(new network_1.NetworkError("Didn't received pong with proper ID")); - } - global.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.onPingMessage = function (message) { - var receviedPingID = message[0]; - this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); - }; - return WebSocketTransport; -}()); -exports.default = WebSocketTransport; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(4); -var host_base_1 = __webpack_require__(10); -var logger_1 = __webpack_require__(2); -var Instance = (function () { - function Instance(options) { - if (!options.locator) { - throw new Error('Expected `locator` property in Instance options!'); - } - var splitInstanceLocator = options.locator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instance locator property is in the wrong format!'); - } - if (!options.serviceName) { - throw new Error('Expected `serviceName` property in Instance options!'); - } - if (!options.serviceVersion) { - throw new Error('Expected `serviceVersion` property in Instance otpions!'); - } - this.platformVersion = splitInstanceLocator[0]; - this.cluster = splitInstanceLocator[1]; - this.id = splitInstanceLocator[2]; - this.serviceName = options.serviceName; - this.serviceVersion = options.serviceVersion; - this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.client = - options.client || - new base_client_1.BaseClient({ - encrypted: options.encrypted, - host: this.host, - logger: this.logger, - }); - this.tokenProvider = options.tokenProvider; - } - Instance.prototype.request = function (options, tokenParams) { - options.path = this.absPath(options.path); - if (options.headers == null || options.headers === undefined) { - options.headers = {}; - } - options.tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.request(options, tokenParams); - }; - Instance.prototype.subscribeNonResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); - }; - Instance.prototype.subscribeResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); - }; - Instance.prototype.absPath = function (relativePath) { - return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) - .replace(/\/+/g, '/') - .replace(/\/+$/, ''); - }; - return Instance; -}()); -exports.default = Instance; - - -/***/ }) -/******/ ]); - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var global_user_store_1 = __webpack_require__(10); -var payload_deserializer_1 = __webpack_require__(0); -var token_provider_1 = __webpack_require__(6); -var user_subscription_1 = __webpack_require__(21); -var ChatManager = (function () { - function ChatManager(options) { - if (typeof options.userId !== 'string') { - throw new Error('Please provide a userId to the ChatManger constructor!'); - } - this.userId = options.userId; - var splitInstanceLocator = options.instanceLocator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instanceLocator property is in the wrong format!'); - } - var cluster = splitInstanceLocator[1]; - var baseClient = options.baseClient || - new pusher_platform_1.BaseClient({ - host: cluster + "." + pusher_platform_1.HOST_BASE, - logger: options.logger, - }); - if (options.tokenProvider instanceof token_provider_1.default) { - options.tokenProvider.userId = this.userId; - } - var sharedInstanceOptions = { - client: baseClient, - locator: options.instanceLocator, - logger: options.logger, - tokenProvider: options.tokenProvider, - }; - this.apiInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.filesInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_files', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.cursorsInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_cursors', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.userStore = new global_user_store_1.default({ apiInstance: this.apiInstance }); - } - ChatManager.prototype.connect = function (options) { - var _this = this; - var cursorsReq = this.cursorsInstance - .request({ - method: 'GET', - path: "/cursors/0/users/" + this.userId, - }) - .then(function (res) { - var cursors = JSON.parse(res); - var cursorsByRoom = {}; - cursors.forEach(function (c) { - cursorsByRoom[c.room_id] = payload_deserializer_1.default.createBasicCursorFromPayload(c); - }); - return cursorsByRoom; - }) - .catch(function (err) { - _this.cursorsInstance.logger.verbose('Error getting cursors:', err); - return {}; - }); - this.userSubscription = new user_subscription_1.default({ - apiInstance: this.apiInstance, - connectCompletionHandler: function (currentUser, error) { - if (currentUser) { - currentUser.cursorsReq = cursorsReq - .then(function (cursors) { - currentUser.cursors = cursors; - }); - options.onSuccess(currentUser); - } - else { - options.onError(error); - } - }, - cursorsInstance: this.cursorsInstance, - delegate: options.delegate, - filesInstance: this.filesInstance, - userStore: this.userStore, - }); - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: options.onError, - onEvent: this.userSubscription.handleEvent.bind(this.userSubscription), - }, - path: '/users', - }); - }; - return ChatManager; -}()); -exports.default = ChatManager; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var user_store_core_1 = __webpack_require__(5); -var utils_1 = __webpack_require__(1); -var GlobalUserStore = (function () { - function GlobalUserStore(options) { - this.apiInstance = options.apiInstance; - this.userStoreCore = options.userStoreCore || new user_store_core_1.default(); - } - GlobalUserStore.prototype.addOrMerge = function (user) { - return this.userStoreCore.addOrMerge(user); - }; - GlobalUserStore.prototype.remove = function (id) { - return this.userStoreCore.remove(id); - }; - GlobalUserStore.prototype.user = function (id, onSuccess, onError) { - this.findOrGetUser(id, onSuccess, onError); - }; - GlobalUserStore.prototype.findOrGetUser = function (id, onSuccess, onError) { - var user = this.userStoreCore.find(id); - if (user) { - onSuccess(user); - return; - } - this.getUser(id, onSuccess, onError); - }; - GlobalUserStore.prototype.getUser = function (id, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: "/users/" + id, - }) - .then(function (res) { - var userPayload = JSON.parse(res); - var user = payload_deserializer_1.default.createUserFromPayload(userPayload); - var userToReturn = _this.addOrMerge(user); - onSuccess(userToReturn); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - onError(error); - }); - }; - GlobalUserStore.prototype.handleInitialPresencePayloadsAfterRoomJoin = function (payloads, onComplete) { - this.handleInitialPresencePayloads(payloads, onComplete); - }; - GlobalUserStore.prototype.handleInitialPresencePayloads = function (payloads, onComplete) { - var _this = this; - var presencePayloadPromises = new Array(); - payloads.forEach(function (payload) { - var presencePromise = new Promise(function (resolve, reject) { - _this.user(payload.userId, function (user) { - user.updatePresenceInfoIfAppropriate(payload); - resolve(); - }, function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - reject(); - }); - }); - presencePayloadPromises.push(presencePromise); - }); - utils_1.allPromisesSettled(presencePayloadPromises).then(function () { - onComplete(); - }); - }; - GlobalUserStore.prototype.fetchUsersWithIds = function (userIds, onSuccess, onError) { - var _this = this; - if (userIds.length === 0) { - this.apiInstance.logger.verbose('Requested to fetch users for a list of user ids which was empty'); - onSuccess([]); - return; - } - var userIdsString = userIds.join(','); - var qs = utils_1.queryString({ user_ids: userIdsString }); - this.apiInstance - .request({ - method: 'GET', - path: "/users_by_ids" + qs, - }) - .then(function (res) { - var usersPayload = JSON.parse(res); - var users = usersPayload.map(function (userPayload) { - var user = payload_deserializer_1.default.createUserFromPayload(userPayload); - var addedOrUpdatedUser = _this.userStoreCore.addOrMerge(user); - return addedOrUpdatedUser; - }); - onSuccess(users); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - onError(error); - }); - }; - GlobalUserStore.prototype.initialFetchOfUsersWithIds = function (userIds, onSuccess, onError) { - this.fetchUsersWithIds(userIds, onSuccess, onError); - }; - return GlobalUserStore; -}()); -exports.default = GlobalUserStore; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) - t[p[i]] = s[p[i]]; - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var basic_message_enricher_1 = __webpack_require__(12); -var cursor_subscription_1 = __webpack_require__(13); -var cursor_types_1 = __webpack_require__(14); -var payload_deserializer_1 = __webpack_require__(0); -var presence_subscription_1 = __webpack_require__(15); -var room_store_1 = __webpack_require__(16); -var room_subscription_1 = __webpack_require__(17); -var constants_1 = __webpack_require__(3); -var utils_1 = __webpack_require__(1); -var CurrentUser = (function () { - function CurrentUser(options) { - var rooms = options.rooms, id = options.id, apiInstance = options.apiInstance, filesInstance = options.filesInstance, cursorsInstance = options.cursorsInstance; - var validRooms = rooms || []; - this.id = id; - this.createdAt = options.createdAt; - this.cursors = {}; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.roomStore = new room_store_1.default({ apiInstance: apiInstance, rooms: validRooms }); - this.apiInstance = apiInstance; - this.filesInstance = filesInstance; - this.cursorsInstance = cursorsInstance; - this.userStore = options.userStore; - this.pathFriendlyId = encodeURIComponent(id); - this.typingRequestSent = {}; - } - Object.defineProperty(CurrentUser.prototype, "rooms", { - get: function () { - return this.roomStore.rooms; - }, - enumerable: true, - configurable: true - }); - CurrentUser.prototype.updateWithPropertiesOf = function (currentUser) { - this.updatedAt = currentUser.updatedAt; - this.name = currentUser.name; - this.customData = currentUser.customData; - }; - CurrentUser.prototype.setupPresenceSubscription = function (delegate) { - this.presenceSubscription = new presence_subscription_1.default({ - apiInstance: this.apiInstance, - delegate: delegate, - roomStore: this.roomStore, - userStore: this.userStore, - }); - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: delegate && delegate.error, - onEvent: this.presenceSubscription.handleEvent.bind(this.presenceSubscription), - }, - path: "/users/" + this.id + "/presence", - }); - }; - CurrentUser.prototype.createRoom = function (options, onSuccess, onError) { - var _this = this; - var roomData = { - created_by_id: this.id, - name: options.name, - private: options.private || false, - }; - if (options.addUserIds && options.addUserIds.length > 0) { - roomData['user_ids'] = options.addUserIds; - } - this.apiInstance - .request({ - json: roomData, - method: 'POST', - path: '/rooms', - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var addedOrMergedRoom = _this.roomStore.addOrMerge(room); - _this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error creating room:', error); - onError(error); - }); - }; - CurrentUser.prototype.populateRoomUserStore = function (room) { - var _this = this; - var userPromises = new Array(); - room.userIds.forEach(function (userId) { - var userPromise = new Promise(function (resolve, reject) { - _this.userStore.user(userId, function (user) { - room.userStore.addOrMerge(user); - resolve(); - }, function (error) { - _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room (room.name): " + error); - reject(); - }); - }); - userPromises.push(userPromise); - }); - utils_1.allPromisesSettled(userPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }; - CurrentUser.prototype.addUser = function (id, roomId, onSuccess, onError) { - this.addOrRemoveUsers(roomId, [id], 'add', onSuccess, onError); - }; - CurrentUser.prototype.removeUser = function (id, roomId, onSuccess, onError) { - this.addOrRemoveUsers(roomId, [id], 'remove', onSuccess, onError); - }; - CurrentUser.prototype.updateRoom = function (roomId, options, onSuccess, onError) { - var _this = this; - if (options.name === undefined && options.isPrivate === undefined) { - onSuccess(); - return; - } - var roomPayload = {}; - if (options.name) { - roomPayload['name'] = options.name; - } - if (options.isPrivate) { - roomPayload['private'] = options.isPrivate; - } - this.apiInstance - .request({ - json: roomPayload, - method: 'PUT', - path: "/rooms/" + roomId, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error updating room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.deleteRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'DELETE', - path: "/rooms/" + roomId, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error deleting room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.addOrRemoveUsers = function (roomId, userIds, membershipChange, onSuccess, onError) { - var _this = this; - var usersPayload = { - user_ids: userIds, - }; - this.apiInstance - .request({ - json: usersPayload, - method: 'PUT', - path: "/rooms/" + roomId + "/users/" + membershipChange, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error when attempting to " + membershipChange + " users from room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.joinRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'POST', - path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/join", - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var addedOrMergedRoom = _this.roomStore.addOrMerge(room); - _this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error joining room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.leaveRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'POST', - path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/leave", - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error leaving room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.getJoinedRooms = function (onSuccess, onError) { - this.getUserRooms(false, onSuccess, onError); - }; - CurrentUser.prototype.getJoinableRooms = function (onSuccess, onError) { - this.getUserRooms(true, onSuccess, onError); - }; - CurrentUser.prototype.getUserRooms = function (onlyJoinable, onSuccess, onError) { - var joinableQueryItemValue = onlyJoinable ? 'true' : 'false'; - this.getRooms("/users/" + this.pathFriendlyId + "/rooms?joinable=" + joinableQueryItemValue, onSuccess, onError); - }; - CurrentUser.prototype.getAllRooms = function (onSuccess, onError) { - this.getRooms('/rooms', onSuccess, onError); - }; - CurrentUser.prototype.isTypingIn = function (roomId, onSuccess, onError) { - var _this = this; - var now = Date.now(); - var sent = this.typingRequestSent[roomId]; - var eventName = 'typing_start'; - var eventPayload = { - name: 'typing_start', - user_id: this.id, - }; - if (!sent || now - sent > constants_1.TYPING_REQ_TTL - constants_1.TYPING_REQ_LEEWAY) { - this.typingRequestSent[roomId] = now; - this.apiInstance - .request({ - json: eventPayload, - method: 'POST', - path: "/rooms/" + roomId + "/events", - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - delete _this.typingRequestSent[roomId]; - _this.apiInstance.logger.verbose("Error sending " + eventName + " event in room " + roomId + ":", error); - onError(error); - }); - } - else { - onSuccess(); - } - }; - CurrentUser.prototype.setCursor = function (position, room, onSuccess, onError) { - var _this = this; - if (typeof position !== 'number') { - throw new Error('Cursor position should be a valid number'); - } - this.cursorsInstance - .request({ - json: { position: position }, - method: 'PUT', - path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id + "/users/" + this.id, - }) - .then(onSuccess) - .catch(function (err) { - _this.cursorsInstance.logger.verbose("Error setting cursor in room " + room.name + ":", err); - onError(err); - }); - }; - CurrentUser.prototype.sendMessage = function (options, onSuccess, onError) { - var _this = this; - var attachment = options.attachment, rest = __rest(options, ["attachment"]); - var completeOptions = __assign({ user_id: this.id }, rest); - if (attachment !== undefined) { - if (this.isDataAttachment(attachment)) { - var file = attachment.file, name = attachment.name; - this.uploadFile(file, name, options.roomId) - .then(function (fileRes) { - _this.sendMessageWithCompleteOptions(__assign({ attachment: fileRes, user_id: _this.id }, rest), onSuccess, onError); - }) - .catch(function (error) { - onError(error); - return; - }); - } - else if (this.isLinkAttachment(attachment)) { - var link = attachment.link, type = attachment.type; - completeOptions.attachment = { - resource_link: link, - type: type, - }; - this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); - } - else { - this.apiInstance.logger.debug('Message not sent: invalid attachment property provided: ', attachment); - } - } - else { - this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); - } - }; - CurrentUser.prototype.subscribeToRoom = function (room, roomDelegate, messageLimit) { - var _this = this; - var path = "/rooms/" + room.id; - if (messageLimit !== undefined) { - if (typeof messageLimit !== 'number') { - throw new Error('Message limit should be a valid number'); - } - path = path + "?message_limit=" + messageLimit; - } - this.cursorsReq.then(function () { - room.subscription = new room_subscription_1.default({ - basicMessageEnricher: new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger), - delegate: roomDelegate, - logger: _this.apiInstance.logger, - }); - _this.apiInstance.subscribeNonResuming({ - listeners: { - onError: roomDelegate.error, - onEvent: room.subscription.handleEvent.bind(room.subscription), - }, - path: path, - }); - _this.subscribeToCursors(room, roomDelegate); - }); - }; - CurrentUser.prototype.fetchMessagesFromRoom = function (room, fetchOptions, onSuccess, onError) { - var _this = this; - var initialIdQueryParam = fetchOptions.initialId - ? "initial_id=" + fetchOptions.initialId - : ''; - var limitQueryParam = fetchOptions.limit - ? "limit=" + fetchOptions.limit - : ''; - var directionQueryParam = fetchOptions.direction - ? "direction=" + fetchOptions.direction - : 'direction=older'; - var combinedQueryParams = [ - initialIdQueryParam, - limitQueryParam, - directionQueryParam, - ].join('&'); - this.apiInstance - .request({ - method: 'GET', - path: "/rooms/" + room.id + "/messages?" + combinedQueryParams, - }) - .then(function (res) { - var messagesPayload = JSON.parse(res); - var messages = new Array(); - var basicMessages = new Array(); - var messageUserIds = messagesPayload.map(function (messagePayload) { - var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(messagePayload); - basicMessages.push(basicMessage); - return basicMessage.id; - }); - var messageUserIdsSet = new Set(messageUserIds); - var userIdsToFetch = Array.from(messageUserIdsSet.values()); - _this.userStore.fetchUsersWithIds(userIdsToFetch, function (users) { - var messageEnricher = new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger); - var enrichmentPromises = new Array(); - basicMessages.forEach(function (basicMessage) { - var enrichmentPromise = new Promise(function (resolve, reject) { - messageEnricher.enrich(basicMessage, function (message) { - messages.push(message); - resolve(); - }, function (error) { - _this.apiInstance.logger.verbose("Unable to enrich basic mesage " + basicMessage.id + ": " + error); - reject(); - }); - }); - enrichmentPromises.push(enrichmentPromise); - }); - utils_1.allPromisesSettled(enrichmentPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - onSuccess(messages.sort(function (msgOne, msgTwo) { return msgOne.id - msgTwo.id; })); - }); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching users with ids " + userIdsToFetch + ":", error); - }); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error fetching messages froom room " + room.name + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.fetchAttachment = function (attachmentURL) { - if (!this.apiInstance.tokenProvider) { - return new Promise(function (resolve, reject) { - reject(new Error('Token provider not set on apiInstance')); - }); - } - return this.apiInstance.tokenProvider.fetchToken().then(function (token) { - return pusher_platform_1.sendRawRequest({ - headers: { - Authorization: "Bearer " + token, - }, - method: 'GET', - url: attachmentURL, - }).then(function (res) { - var attachmentPayload = JSON.parse(res); - var fetchedAttachment = payload_deserializer_1.default.createFetchedAttachmentFromPayload(attachmentPayload); - return fetchedAttachment; - }); - }); - }; - CurrentUser.prototype.isDataAttachment = function (attachment) { - return (attachment.file !== undefined && - attachment.name !== undefined); - }; - CurrentUser.prototype.isLinkAttachment = function (attachment) { - return (attachment.link !== undefined && - attachment.type !== undefined); - }; - CurrentUser.prototype.uploadFile = function (file, fileName, roomId) { - var data = new FormData(); - data.append('file', file, fileName); - return this.filesInstance - .request({ - body: data, - method: 'POST', - path: "/rooms/" + roomId + "/files/" + fileName, - }) - .then(function (res) { - return JSON.parse(res); - }); - }; - CurrentUser.prototype.sendMessageWithCompleteOptions = function (options, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - json: options, - method: 'POST', - path: "/rooms/" + options.roomId + "/messages", - }) - .then(function (res) { - var messageIdPayload = JSON.parse(res); - var messageId = messageIdPayload.message_id; - onSuccess(messageId); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error sending message to room " + options.roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.subscribeToCursors = function (room, roomDelegate) { - var _this = this; - room.cursorSubscription = new cursor_subscription_1.default({ - delegate: roomDelegate, - handleCursorSetInternal: function (cursor) { - if (cursor.userId === _this.id && _this.cursors !== undefined) { - _this.cursors[cursor.roomId] = cursor; - } - }, - logger: this.cursorsInstance.logger, - room: room, - userStore: this.userStore, - }); - this.cursorsInstance.subscribeNonResuming({ - listeners: { - onEvent: room.cursorSubscription.handleEvent.bind(room.cursorSubscription), - }, - path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id, - }); - }; - CurrentUser.prototype.getRooms = function (path, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: path, - }) - .then(function (res) { - var roomsPayload = JSON.parse(res); - var rooms = roomsPayload.map(function (roomPayload) { - return payload_deserializer_1.default.createRoomFromPayload(roomPayload); - }); - onSuccess(rooms); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error when getting instance rooms:', error); - onError(error); - }); - }; - return CurrentUser; -}()); -exports.default = CurrentUser; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var BasicMessageEnricher = (function () { - function BasicMessageEnricher(userStore, room, logger) { - this.completionOrderList = []; - this.messageIdToCompletionHandlers = {}; - this.enrichedMessagesAwaitingCompletionCalls = {}; - this.userIdsBeingRetrieved = []; - this.userIdsToBasicMessageIds = {}; - this.messagesAwaitingEnrichmentDependentOnUserRetrieval = {}; - this.userStore = userStore; - this.room = room; - this.logger = logger; - } - BasicMessageEnricher.prototype.enrich = function (basicMessage, onSuccess, onError) { - var _this = this; - var basicMessageId = basicMessage.id; - var basicMessageSenderId = basicMessage.senderId; - this.completionOrderList.push(basicMessageId); - this.messageIdToCompletionHandlers[basicMessageId] = { - onError: onError, - onSuccess: onSuccess, - }; - if (this.userIdsToBasicMessageIds[basicMessageSenderId] === undefined) { - this.userIdsToBasicMessageIds[basicMessageSenderId] = [basicMessageId]; - } - else { - this.userIdsToBasicMessageIds[basicMessageSenderId].push(basicMessageId); - } - this.messagesAwaitingEnrichmentDependentOnUserRetrieval[basicMessageId] = basicMessage; - if (this.userIdsBeingRetrieved.indexOf(basicMessageSenderId) > -1) { - return; - } - else { - this.userIdsBeingRetrieved.push(basicMessageSenderId); - } - this.userStore.user(basicMessageSenderId, function (user) { - var basicMessageIds = _this.userIdsToBasicMessageIds[basicMessageSenderId]; - if (basicMessageIds === undefined) { - _this.logger.verbose("Fetched user information for user with id " + user.id + " but no messages needed information for this user"); - return; - } - var basicMessages = basicMessageIds - .map(function (bmId) { - return _this.messagesAwaitingEnrichmentDependentOnUserRetrieval[bmId]; - }) - .filter(function (el) { return el !== undefined; }); - _this.enrichMessagesWithUser(user, basicMessages); - var indexToRemove = _this.userIdsBeingRetrieved.indexOf(basicMessageSenderId); - if (indexToRemove > -1) { - _this.userIdsBeingRetrieved.splice(indexToRemove, 1); - } - }, function (error) { - _this.logger.debug("Unable to find user with id " + basicMessage.senderId + ", associated with message " + basicMessageId + ". Error:", error); - _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessageId, error); - }); - }; - BasicMessageEnricher.prototype.enrichMessagesWithUser = function (user, messages) { - var _this = this; - messages.forEach(function (basicMessage) { - var message = { - attachment: basicMessage.attachment, - createdAt: basicMessage.createdAt, - id: basicMessage.id, - room: _this.room, - sender: user, - text: basicMessage.text, - updatedAt: basicMessage.updatedAt, - }; - _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessage.id, message); - }); - }; - BasicMessageEnricher.prototype.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo = function (id, result) { - var nextIdToComplete = this.completionOrderList[0]; - if (nextIdToComplete === undefined) { - return; - } - this.enrichedMessagesAwaitingCompletionCalls[id] = result; - if (id !== nextIdToComplete) { - this.logger.verbose("Waiting to call completion handler for message id " + id + " as there are other older messages still to be enriched"); - return; - } - do { - var messageId = this.completionOrderList[0]; - var completionHandler = this.messageIdToCompletionHandlers[messageId]; - if (completionHandler === undefined) { - this.logger.verbose("Completion handler not stored for message id " + messageId); - return; - } - var res = this.enrichedMessagesAwaitingCompletionCalls[messageId]; - if (res === undefined) { - this.logger.verbose("Enrichment result not stored for message id " + messageId); - return; - } - if (res.sender !== undefined) { - completionHandler.onSuccess(res); - } - else { - completionHandler.onError(res); - } - this.completionOrderList.shift(); - delete this.messageIdToCompletionHandlers[messageId]; - delete this.enrichedMessagesAwaitingCompletionCalls[messageId]; - } while (this.completionOrderList[0] !== undefined && - this.enrichedMessagesAwaitingCompletionCalls[this.completionOrderList[0]] !== undefined); - }; - return BasicMessageEnricher; -}()); -exports.default = BasicMessageEnricher; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var CursorSubscription = (function () { - function CursorSubscription(options) { - this.delegate = options.delegate; - this.logger = options.logger; - this.room = options.room; - this.userStore = options.userStore; - this.handleCursorSetInternal = options.handleCursorSetInternal; - } - CursorSubscription.prototype.handleEvent = function (event) { - var _this = this; - if (!this.delegate || !this.delegate.cursorSet) { - return; - } - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - if (eventName !== 'cursor_set') { - this.logger.verbose("Cursor subscription received event with type " + eventName + ", when 'cursor_set' was expected"); - return; - } - this.logger.verbose("Received event name: " + eventName + ", and data: " + data); - var basicCursor = payload_deserializer_1.default.createBasicCursorFromPayload(data); - this.logger.verbose("Room received cursor for: " + basicCursor.userId); - this.handleCursorSetInternal(basicCursor); - this.enrich(basicCursor, function (cursor) { - if (_this.delegate && _this.delegate.cursorSet) { - _this.delegate.cursorSet(cursor); - } - }, function (error) { - _this.logger.debug('Error receiving cursor:', error); - }); - }; - CursorSubscription.prototype.enrich = function (basicCursor, onSuccess, onError) { - var _this = this; - this.userStore.user(basicCursor.userId, function (user) { - onSuccess({ - cursorType: basicCursor.cursorType, - position: basicCursor.position, - room: _this.room, - updatedAt: basicCursor.updatedAt, - user: user, - }); - }, function (error) { - _this.logger.debug("Unable to find user with id " + basicCursor.userId + ". Error:", error); - onError(error); - }); - }; - return CursorSubscription; -}()); -exports.default = CursorSubscription; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var CursorType; -(function (CursorType) { - CursorType[CursorType["Read"] = 0] = "Read"; -})(CursorType || (CursorType = {})); -exports.default = CursorType; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var PresenceSubscription = (function () { - function PresenceSubscription(options) { - this.apiInstance = options.apiInstance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.delegate = options.delegate; - } - PresenceSubscription.prototype.handleEvent = function (event) { - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - this.apiInstance.logger.verbose("Received event type: " + eventName + ", and data: " + data); - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'presence_update': - this.parsePresenceUpdatePayload(eventName, data, this.userStore); - break; - case 'join_room_presence_update': - this.parseJoinRoomPresenceUpdatePayload(eventName, data, this.userStore); - break; - default: - this.apiInstance.logger.verbose("Unsupported event type received: " + eventName + ", and data: " + data); - break; - } - }; - PresenceSubscription.prototype.end = function () { - }; - PresenceSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { - var _this = this; - var userStatesPayload = data.user_states; - if (userStatesPayload === undefined || - userStatesPayload.constructor !== Array) { - this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); - return; - } - var userStates = userStatesPayload - .map(function (userStatePayload) { - return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); - }) - .filter(function (el) { return el !== undefined; }); - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - this.userStore.handleInitialPresencePayloads(userStates, function () { - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }); - }; - PresenceSubscription.prototype.parsePresenceUpdatePayload = function (eventName, data, userStore) { - var _this = this; - var presencePayload = payload_deserializer_1.default.createPresencePayloadFromPayload(data); - userStore.user(presencePayload.userId, function (user) { - user.updatePresenceInfoIfAppropriate(presencePayload); - switch (presencePayload.state.stringValue) { - case 'online': - if (_this.delegate && _this.delegate.userCameOnline) { - _this.delegate.userCameOnline(user); - } - _this.apiInstance.logger.verbose(user.id + " came online"); - break; - case 'offline': - if (_this.delegate && _this.delegate.userWentOffline) { - _this.delegate.userWentOffline(user); - } - _this.apiInstance.logger.verbose(user.id + " went offline"); - break; - case 'unknown': - _this.apiInstance.logger.verbose("Somehow the presence state of user " + user.id + " is unknown"); - break; - } - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - return; - } - if (room.userIds.indexOf(user.id) > -1) { - switch (presencePayload.state.stringValue) { - case 'online': - if (room.subscription.delegate && - room.subscription.delegate.userCameOnlineInRoom) { - room.subscription.delegate.userCameOnlineInRoom(user); - } - break; - case 'offline': - if (room.subscription.delegate && - room.subscription.delegate.userWentOfflineInRoom) { - room.subscription.delegate.userWentOfflineInRoom(user); - } - break; - default: - break; - } - } - }); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching user information for user with id " + presencePayload.userId + ":", error); - return; - }); - }; - PresenceSubscription.prototype.parseJoinRoomPresenceUpdatePayload = function (eventName, data, userStore) { - var _this = this; - var userStatesPayload = data.user_states; - if (userStatesPayload === undefined || - userStatesPayload.constructor !== Array) { - this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); - return; - } - var userStates = userStatesPayload - .map(function (userStatePayload) { - return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); - }) - .filter(function (el) { return el !== undefined; }); - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - this.userStore.handleInitialPresencePayloads(userStates, function () { - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }); - }; - return PresenceSubscription; -}()); -exports.default = PresenceSubscription; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var RoomStore = (function () { - function RoomStore(options) { - this.rooms = options.rooms; - this.apiInstance = options.apiInstance; - } - RoomStore.prototype.room = function (id, onSuccess, onError) { - this.findOrGetRoom(id, onSuccess, onError); - }; - RoomStore.prototype.addOrMerge = function (room) { - var existingRoom = this.rooms.find(function (el) { return el.id === room.id; }); - if (existingRoom) { - existingRoom.updateWithPropertiesOfRoom(room); - return existingRoom; - } - else { - this.rooms.push(room); - return room; - } - }; - RoomStore.prototype.remove = function (id) { - var indexOfRoom = this.rooms.findIndex(function (el) { return el.id === id; }); - if (indexOfRoom === -1) { - return undefined; - } - var room = this.rooms[indexOfRoom]; - this.rooms.splice(indexOfRoom, 1); - return room; - }; - RoomStore.prototype.findOrGetRoom = function (id, onSuccess, onError) { - var room = this.rooms.find(function (el) { return el.id === id; }); - if (room) { - onSuccess(room); - } - else { - this.getRoom(id, onSuccess, onError); - } - }; - RoomStore.prototype.getRoom = function (id, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: "/rooms/" + id, - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - onSuccess(room); - }) - .catch(function (error) { - _this.apiInstance.logger.debug("Error fetching room " + id + ":", error); - onError(error); - }); - }; - return RoomStore; -}()); -exports.default = RoomStore; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var RoomSubscription = (function () { - function RoomSubscription(options) { - this.delegate = options.delegate; - this.basicMessageEnricher = options.basicMessageEnricher; - this.logger = options.logger; - } - RoomSubscription.prototype.handleEvent = function (event) { - var _this = this; - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - if (eventName !== 'new_message') { - this.logger.verbose("Room subscription received event with type " + eventName + ", when 'new_message' was expected"); - return; - } - this.logger.verbose("Received event name: " + eventName + ", and data:", data); - var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(data); - this.basicMessageEnricher.enrich(basicMessage, function (message) { - _this.logger.verbose("Room received new message: " + message.text); - if (_this.delegate && _this.delegate.newMessage) { - _this.delegate.newMessage(message); - } - }, function (error) { - _this.logger.debug('Error receiving new message:', error); - }); - }; - return RoomSubscription; -}()); -exports.default = RoomSubscription; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var room_user_store_1 = __webpack_require__(19); -var Room = (function () { - function Room(options) { - this.id = options.id; - this.name = options.name; - this.isPrivate = options.isPrivate; - this.createdByUserId = options.createdByUserId; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.deletedAt = options.deletedAt; - this.userIds = options.userIds || []; - this.userStore = new room_user_store_1.default(); - } - Room.prototype.updateWithPropertiesOfRoom = function (room) { - this.name = room.name; - this.isPrivate = room.isPrivate; - this.updatedAt = room.updatedAt; - this.deletedAt = room.deletedAt; - this.userIds = room.userIds; - }; - return Room; -}()); -exports.default = Room; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var user_store_core_1 = __webpack_require__(5); -var RoomUserStore = (function () { - function RoomUserStore(userStoreCore) { - if (userStoreCore === void 0) { userStoreCore = new user_store_core_1.default(); } - this.userStoreCore = userStoreCore; - } - RoomUserStore.prototype.addOrMerge = function (user) { - return this.userStoreCore.addOrMerge(user); - }; - RoomUserStore.prototype.remove = function (id) { - return this.userStoreCore.remove(id); - }; - return RoomUserStore; -}()); -exports.default = RoomUserStore; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var presence_state_1 = __webpack_require__(4); -var User = (function () { - function User(options) { - this.id = options.id; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.presenceState = new presence_state_1.default('unknown'); - } - User.prototype.updateWithPropertiesOfUser = function (user) { - if (user.presenceState.stringValue !== 'unknown') { - this.presenceState = user.presenceState; - this.lastSeenAt = user.lastSeenAt; - } - return this; - }; - User.prototype.updatePresenceInfoIfAppropriate = function (newInfoPayload) { - if (newInfoPayload.state.stringValue !== 'unknown') { - this.presenceState = newInfoPayload.state; - this.lastSeenAt = newInfoPayload.lastSeenAt; - } - }; - return User; -}()); -exports.default = User; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var constants_1 = __webpack_require__(3); -var utils_1 = __webpack_require__(1); -var UserSubscription = (function () { - function UserSubscription(options) { - this.typingTimers = {}; - this.apiInstance = options.apiInstance; - this.filesInstance = options.filesInstance; - this.cursorsInstance = options.cursorsInstance; - this.userStore = options.userStore; - this.delegate = options.delegate; - this.connectCompletionHandlers = [options.connectCompletionHandler]; - } - UserSubscription.prototype.handleEvent = function (event) { - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - this.apiInstance.logger.verbose("Received event name: " + eventName + ", and data: " + data); - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'added_to_room': - this.parseAddedToRoomPayload(eventName, data); - break; - case 'removed_from_room': - this.parseRemovedFromRoomPayload(eventName, data); - break; - case 'room_updated': - this.parseRoomUpdatedPayload(eventName, data); - break; - case 'room_deleted': - this.parseRoomDeletedPayload(eventName, data); - break; - case 'user_joined': - this.parseUserJoinedPayload(eventName, data); - break; - case 'user_left': - this.parseUserLeftPayload(eventName, data); - break; - case 'typing_start': - this.parseIsTypingPayload(eventName, data, data.user_id); - break; - case 'typing_stop': - break; - } - }; - UserSubscription.prototype.callConnectCompletionHandlers = function (currentUser, error) { - this.connectCompletionHandlers.forEach(function (completionHandler) { - completionHandler(currentUser, error); - }); - }; - UserSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { - var _this = this; - var roomsPayload = data.rooms; - var userPayload = data.current_user; - var receivedCurrentUser = payload_deserializer_1.default.createCurrentUserFromPayload(userPayload, this.apiInstance, this.filesInstance, this.cursorsInstance, this.userStore); - var wasExistingCurrentUser = this.currentUser !== undefined; - if (this.currentUser) { - this.currentUser.updateWithPropertiesOf(receivedCurrentUser); - } - else { - this.currentUser = receivedCurrentUser; - } - var receivedRoomsConstructor = roomsPayload.constructor; - if (receivedRoomsConstructor !== Array) { - throw TypeError('`rooms` key of initial_state payload was of type `${receivedRoomsConstructor}`, expected `Array`'); - } - if (roomsPayload.length === 0) { - this.currentUser.setupPresenceSubscription(this.delegate); - this.callConnectCompletionHandlers(this.currentUser); - return; - } - var combinedRoomUserIds = new Set([]); - var roomsFromConnection = []; - roomsPayload.forEach(function (roomPayload) { - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - room.userIds.forEach(function (userId) { - combinedRoomUserIds.add(userId); - }); - roomsFromConnection.push(room); - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.roomStore.addOrMerge(room); - }); - this.callConnectCompletionHandlers(this.currentUser); - this.fetchInitialUserInformationForUserIds(combinedRoomUserIds, this.currentUser); - if (wasExistingCurrentUser) { - this.reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection); - } - }; - UserSubscription.prototype.fetchInitialUserInformationForUserIds = function (userIds, currentUser) { - var _this = this; - var userIdsArray = Array.from(userIds.values()); - this.userStore.initialFetchOfUsersWithIds(userIdsArray, function (users) { - var combinedRoomUsersPromises = new Array(); - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.roomStore.rooms.forEach(function (room) { - var roomPromise = new Promise(function (roomResolve, roomReject) { - var roomUsersPromises = new Array(); - room.userIds.forEach(function (userId) { - var userPromise = new Promise(function (userResolve, userReject) { - _this.userStore.user(userId, function (user) { - room.userStore.addOrMerge(user); - userResolve(); - }, function (error) { - _this.apiInstance.logger.verbose("Unable to fetch information about user " + userId); - userReject(); - }); - }); - roomUsersPromises.push(userPromise); - }); - utils_1.allPromisesSettled(roomUsersPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name + "\""); - roomResolve(); - }); - }); - combinedRoomUsersPromises.push(roomPromise); - }); - utils_1.allPromisesSettled(combinedRoomUsersPromises).then(function () { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.setupPresenceSubscription(_this.delegate); - }); - }, function (error) { - _this.apiInstance.logger.debug("Unable to fetch user information after successful connection: " + error); - return; - }); - }; - UserSubscription.prototype.reconcileExistingRoomStoreWithRoomsReceivedOnConnection = function (roomsFromConnection) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property of UserSubscription unset after successful connection'); - return; - } - var roomStoreRooms = this.currentUser.roomStore.rooms; - var mostRecentConnectionRoomsSet = new Set(roomsFromConnection); - var noLongerAMemberOfRooms = roomStoreRooms.filter(function (room) { return !mostRecentConnectionRoomsSet.has(room); }); - noLongerAMemberOfRooms.forEach(function (room) { - if (_this.delegate && _this.delegate.removedFromRoom) { - _this.delegate.removedFromRoom(room); - } - }); - }; - UserSubscription.prototype.parseAddedToRoomPayload = function (eventName, data) { - var _this = this; - var roomPayload = data.room; - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose("`room` key missing or invalid in `added_to_room` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var roomAdded = this.currentUser.roomStore.addOrMerge(room); - if (this.delegate && this.delegate.addedToRoom) { - this.delegate.addedToRoom(room); - } - this.apiInstance.logger.verbose("Added to room: " + room.name); - var roomUsersPromises = new Array(); - roomAdded.userIds.forEach(function (userId) { - var userPromise = new Promise(function (resolve, reject) { - _this.userStore.user(userId, function (user) { - _this.apiInstance.logger.verbose("Added user id " + userId + " to room " + room.name); - room.userStore.addOrMerge(user); - resolve(); - }, function (error) { - _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room " + room.name + ": " + error); - reject(); - }); - }); - roomUsersPromises.push(userPromise); - }); - utils_1.allPromisesSettled(roomUsersPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }; - UserSubscription.prototype.parseRemovedFromRoomPayload = function (eventName, data) { - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `removed_from_room` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var roomRemoved = this.currentUser.roomStore.remove(roomId); - if (roomRemoved) { - if (this.delegate && this.delegate.removedFromRoom) { - this.delegate.removedFromRoom(roomRemoved); - } - this.apiInstance.logger.verbose("Removed from room: " + roomRemoved.name); - } - else { - this.apiInstance.logger.verbose("Received `removed_from_room` API event but room with ID " + roomId + " not found in local store of joined rooms"); - return; - } - }; - UserSubscription.prototype.parseRoomUpdatedPayload = function (eventName, data) { - var _this = this; - var roomPayload = data.room; - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose("`room` key missing or invalid in `room_updated` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - this.currentUser.roomStore.room(room.id, function (roomToUpdate) { - roomToUpdate.updateWithPropertiesOfRoom(room); - if (_this.delegate && _this.delegate.roomUpdated) { - _this.delegate.roomUpdated(roomToUpdate); - } - _this.apiInstance.logger.verbose("Room updated: " + room.name); - }, function (error) { - _this.apiInstance.logger.debug("Error updating room " + room.id + ":", error); - }); - }; - UserSubscription.prototype.parseRoomDeletedPayload = function (eventName, data) { - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `room_deleted` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var deletedRoom = this.currentUser.roomStore.remove(roomId); - if (deletedRoom) { - if (this.delegate && this.delegate.roomDeleted) { - this.delegate.roomDeleted(deletedRoom); - } - this.apiInstance.logger.verbose("Room deleted: " + deletedRoom.name); - } - else { - this.apiInstance.logger.verbose("Received `room_deleted` API event but room with ID " + roomId + " not found in local store of joined rooms"); - return; - } - }; - UserSubscription.prototype.parseUserJoinedPayload = function (eventName, data) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_joined` payload: " + data); - return; - } - var userId = data.user_id; - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_joined` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - var addedOrMergedUser = room.userStore.addOrMerge(user); - if (room.userIds.indexOf(addedOrMergedUser.id) === -1) { - room.userIds.push(addedOrMergedUser.id); - } - if (_this.delegate && _this.delegate.userJoinedRoom) { - _this.delegate.userJoinedRoom(room, addedOrMergedUser); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userJoined) { - room.subscription.delegate.userJoined(addedOrMergedUser); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " joined room: " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); - return; - }); - }; - UserSubscription.prototype.parseUserLeftPayload = function (eventName, data) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_left` payload: " + data); - return; - } - var userId = data.user_id; - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_left` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - var roomUserIdIndex = room.userIds.indexOf(user.id); - if (roomUserIdIndex > -1) { - room.userIds.splice(roomUserIdIndex, 1); - } - room.userStore.remove(user.id); - if (_this.delegate && _this.delegate.userLeftRoom) { - _this.delegate.userLeftRoom(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userLeft) { - room.subscription.delegate.userLeft(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " left room " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " left room with id " + roomId + " but no information about the user could be retrieved. Error was: " + error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); - return; - }); - }; - UserSubscription.prototype.parseIsTypingPayload = function (eventName, data, userId) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `typing_start` payload: " + data); - return; - } - if (!this.typingTimers[roomId]) { - this.typingTimers[roomId] = {}; - } - if (this.typingTimers[roomId][userId]) { - clearTimeout(this.typingTimers[roomId][userId]); - } - else { - this.startedTyping(roomId, userId); - } - this.typingTimers[roomId][userId] = setTimeout(function () { - _this.stoppedTyping(roomId, userId); - delete _this.typingTimers[roomId][userId]; - }, constants_1.TYPING_REQ_TTL); - }; - UserSubscription.prototype.startedTyping = function (roomId, userId) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - if (_this.delegate && _this.delegate.userStartedTyping) { - _this.delegate.userStartedTyping(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userStartedTyping) { - room.subscription.delegate.userStartedTyping(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " started typing in room " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching information for user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching information for room " + roomId + ":", error); - return; - }); - }; - UserSubscription.prototype.stoppedTyping = function (roomId, userId) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - if (_this.delegate && _this.delegate.userStoppedTyping) { - _this.delegate.userStoppedTyping(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userStoppedTyping) { - room.subscription.delegate.userStoppedTyping(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " stopped typing in room " + room.name); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching information for user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching information for room " + roomId + ":", error); - return; - }); - }; - return UserSubscription; -}()); -exports.default = UserSubscription; - - -/***/ }) -/******/ ]); \ No newline at end of file diff --git a/dist/react-native/declarations/attachment.d.ts b/dist/react-native/declarations/attachment.d.ts deleted file mode 100644 index 1e89409..0000000 --- a/dist/react-native/declarations/attachment.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface Attachment { - fetchRequired: boolean; - link: string; - type: string; -} -export default Attachment; diff --git a/dist/react-native/declarations/basic_cursor.d.ts b/dist/react-native/declarations/basic_cursor.d.ts deleted file mode 100644 index 1ab80b5..0000000 --- a/dist/react-native/declarations/basic_cursor.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface BasicCursor { - cursorType: number; - position: number; - roomId: number; - updatedAt: string; - userId: string; -} -export default BasicCursor; diff --git a/dist/react-native/declarations/basic_message.d.ts b/dist/react-native/declarations/basic_message.d.ts deleted file mode 100644 index b28e155..0000000 --- a/dist/react-native/declarations/basic_message.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Attachment from './attachment'; -interface BasicMessage { - id: number; - senderId: string; - roomId: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; -} -export default BasicMessage; diff --git a/dist/react-native/declarations/basic_message_enricher.d.ts b/dist/react-native/declarations/basic_message_enricher.d.ts deleted file mode 100644 index a8f7e15..0000000 --- a/dist/react-native/declarations/basic_message_enricher.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Logger } from 'pusher-platform'; -import BasicMessage from './basic_message'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import Room from './room'; -import User from './user'; -export interface MessageEnrichmentCompletionHandlers { - onSuccess: (message: Message) => void; - onError: (error: any) => void; -} -export declare type MessageIdsToCompletionHandlers = { - [key: number]: MessageEnrichmentCompletionHandlers; -}; -export declare type UserIdsToBasicMessageIds = { - [key: string]: number[]; -}; -export declare type MessageEnrichmentResult = Message | any; -export declare type MessageIdsToEnrichmentResults = { - [key: number]: MessageEnrichmentResult; -}; -export declare type MessageIdsToBasicMessages = { - [key: number]: BasicMessage; -}; -export default class BasicMessageEnricher { - userStore: GlobalUserStore; - room: Room; - logger: Logger; - private completionOrderList; - private messageIdToCompletionHandlers; - private enrichedMessagesAwaitingCompletionCalls; - private userIdsBeingRetrieved; - private userIdsToBasicMessageIds; - private messagesAwaitingEnrichmentDependentOnUserRetrieval; - constructor(userStore: GlobalUserStore, room: Room, logger: Logger); - enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; - enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; - callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; -} diff --git a/dist/react-native/declarations/basic_user.d.ts b/dist/react-native/declarations/basic_user.d.ts deleted file mode 100644 index fb90490..0000000 --- a/dist/react-native/declarations/basic_user.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface BasicUser { - id: string; - createdAt: string; - updatedAt: string; -} -export default BasicUser; diff --git a/dist/react-native/declarations/chat_manager.d.ts b/dist/react-native/declarations/chat_manager.d.ts deleted file mode 100644 index 49a8817..0000000 --- a/dist/react-native/declarations/chat_manager.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -export interface ChatManagerOptions { - instanceLocator: string; - tokenProvider: TokenProvider; - logger?: Logger; - baseClient?: BaseClient; - userId: string; -} -export default class ChatManager { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userId: string; - private userStore; - private userSubscription; - constructor(options: ChatManagerOptions); - connect(options: ConnectOptions): void; -} -export interface ConnectOptions { - delegate?: ChatManagerDelegate; - onSuccess: (currentUser: CurrentUser) => void; - onError: (error: any) => void; -} diff --git a/dist/react-native/declarations/chat_manager_delegate.d.ts b/dist/react-native/declarations/chat_manager_delegate.d.ts deleted file mode 100644 index 5b2d790..0000000 --- a/dist/react-native/declarations/chat_manager_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Room from './room'; -import User from './user'; -interface ChatManagerDelegate { - addedToRoom?: (room: Room) => void; - removedFromRoom?: (room: Room) => void; - roomUpdated?: (room: Room) => void; - roomDeleted?: (room: Room) => void; - userStartedTyping?: (room: Room, user: User) => void; - userStoppedTyping?: (room: Room, user: User) => void; - userJoinedRoom?: (room: Room, user: User) => void; - userLeftRoom?: (room: Room, user: User) => void; - userCameOnline?: (user: User) => void; - userWentOffline?: (user: User) => void; - error?: (error: any) => void; -} -export default ChatManagerDelegate; diff --git a/dist/react-native/declarations/constants.d.ts b/dist/react-native/declarations/constants.d.ts deleted file mode 100644 index d18fd38..0000000 --- a/dist/react-native/declarations/constants.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare const TYPING_REQ_TTL = 1500; -export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/react-native/declarations/current_user.d.ts b/dist/react-native/declarations/current_user.d.ts deleted file mode 100644 index 77a8eae..0000000 --- a/dist/react-native/declarations/current_user.d.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Instance } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import PresenceSubscription from './presence_subscription'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -import RoomStore from './room_store'; -export interface CreateRoomOptions { - name: string; - private?: boolean; - addUserIds?: string[]; -} -export interface UpdateRoomOptions { - name?: string; - isPrivate?: boolean; -} -export interface FetchRoomMessagesOptions { - initialId?: string; - limit?: number; - direction?: string; -} -export interface CurrentUserOptions { - id: string; - createdAt: string; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - rooms?: Room[]; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; -} -export interface DataAttachment { - file: Blob; - name: string; -} -export interface LinkAttachment { - link: string; - type: string; -} -export declare type GenericAttachment = LinkAttachment | DataAttachment; -export interface AttachmentBody { - resource_link: string; - type: string; -} -export interface SendMessageOptions { - attachment?: GenericAttachment; - roomId: number; - text?: string; -} -export interface CompleteMessageOptions { - attachment?: AttachmentBody; - roomId: number; - text?: string; - user_id: string; -} -export default class CurrentUser { - id: string; - createdAt: string; - cursors: { - [roomId: string]: BasicCursor; - }; - cursorsReq: Promise; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - userStore: GlobalUserStore; - roomStore: RoomStore; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - pathFriendlyId: string; - presenceSubscription: PresenceSubscription; - typingRequestSent: { - [roomId: string]: number; - }; - readonly rooms: Room[]; - constructor(options: CurrentUserOptions); - updateWithPropertiesOf(currentUser: CurrentUser): void; - setupPresenceSubscription(delegate?: ChatManagerDelegate): void; - createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - populateRoomUserStore(room: Room): void; - addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; - deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; - joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; - sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; - subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; - fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; - fetchAttachment(attachmentURL: string): Promise; - private isDataAttachment(attachment); - private isLinkAttachment(attachment); - private uploadFile(file, fileName, roomId); - private sendMessageWithCompleteOptions(options, onSuccess, onError); - private subscribeToCursors(room, roomDelegate); - private getRooms(path, onSuccess, onError); -} diff --git a/dist/react-native/declarations/cursor.d.ts b/dist/react-native/declarations/cursor.d.ts deleted file mode 100644 index 3aa3524..0000000 --- a/dist/react-native/declarations/cursor.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Room from './room'; -import User from './user'; -interface Cursor { - cursorType: number; - position: number; - room: Room; - updatedAt: string; - user: User; -} -export default Cursor; diff --git a/dist/react-native/declarations/cursor_subscription.d.ts b/dist/react-native/declarations/cursor_subscription.d.ts deleted file mode 100644 index 08e991b..0000000 --- a/dist/react-native/declarations/cursor_subscription.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import Cursor from './cursor'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -export interface CursorSubscriptionOptions { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; -} -export default class CursorSubscription { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; - constructor(options: CursorSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; -} diff --git a/dist/react-native/declarations/cursor_types.d.ts b/dist/react-native/declarations/cursor_types.d.ts deleted file mode 100644 index 01f22f7..0000000 --- a/dist/react-native/declarations/cursor_types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare enum CursorType { - Read = 0, -} -export default CursorType; diff --git a/dist/react-native/declarations/fetched_attachment.d.ts b/dist/react-native/declarations/fetched_attachment.d.ts deleted file mode 100644 index 907eddc..0000000 --- a/dist/react-native/declarations/fetched_attachment.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface FetchedAttachmentFile { - bytes: number; - lastModified: number; - name: string; -} -interface FetchedAttachment { - file: FetchedAttachmentFile; - link: string; - ttl: number; -} -export default FetchedAttachment; diff --git a/dist/react-native/declarations/global_user_store.d.ts b/dist/react-native/declarations/global_user_store.d.ts deleted file mode 100644 index 7712fe4..0000000 --- a/dist/react-native/declarations/global_user_store.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import PresencePayload from './presence_payload'; -import User from './user'; -import UserStoreCore from './user_store_core'; -export interface GlobalUserStoreOptions { - apiInstance: Instance; - userStoreCore?: UserStoreCore; -} -export default class GlobalUserStore { - private apiInstance; - private userStoreCore; - constructor(options: GlobalUserStoreOptions); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; - handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; - fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; - initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; -} diff --git a/dist/react-native/declarations/index.d.ts b/dist/react-native/declarations/index.d.ts deleted file mode 100644 index 8118af7..0000000 --- a/dist/react-native/declarations/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BaseClient } from 'pusher-platform'; -import ChatManager from './chat_manager'; -import TokenProvider from './token_provider'; -export { BaseClient, ChatManager, TokenProvider }; -declare const _default: { - BaseClient: typeof BaseClient; - ChatManager: typeof ChatManager; - TokenProvider: typeof TokenProvider; -}; -export default _default; diff --git a/dist/react-native/declarations/message.d.ts b/dist/react-native/declarations/message.d.ts deleted file mode 100644 index d7bd58d..0000000 --- a/dist/react-native/declarations/message.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Attachment from './attachment'; -import Room from './room'; -import User from './user'; -interface Message { - id: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; - sender: User; - room: Room; -} -export default Message; diff --git a/dist/react-native/declarations/payload_deserializer.d.ts b/dist/react-native/declarations/payload_deserializer.d.ts deleted file mode 100644 index bb635f2..0000000 --- a/dist/react-native/declarations/payload_deserializer.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Attachment from './attachment'; -import BasicCursor from './basic_cursor'; -import BasicMessage from './basic_message'; -import BasicUser from './basic_user'; -import CurrentUser from './current_user'; -import FetchedAttachment from './fetched_attachment'; -import GlobalUserStore from './global_user_store'; -import PresencePayload from './presence_payload'; -import Room from './room'; -import User from './user'; -export default class PayloadDeserializer { - static createUserFromPayload(userPayload: any): User; - static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; - static createRoomFromPayload(roomPayload: any): Room; - static createBasicMessageFromPayload(messagePayload: any): BasicMessage; - static createBasicCursorFromPayload(payload: any): BasicCursor; - static createPresencePayloadFromPayload(payload: any): PresencePayload; - static createBasicUserFromPayload(payload: any): BasicUser; - static createAttachmentFromPayload(payload: any): Attachment | undefined; - static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; -} diff --git a/dist/react-native/declarations/presence_payload.d.ts b/dist/react-native/declarations/presence_payload.d.ts deleted file mode 100644 index c2a2215..0000000 --- a/dist/react-native/declarations/presence_payload.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import PresenceState from './presence_state'; -interface PresencePayload { - userId: string; - state: PresenceState; - lastSeenAt?: string; -} -export default PresencePayload; diff --git a/dist/react-native/declarations/presence_state.d.ts b/dist/react-native/declarations/presence_state.d.ts deleted file mode 100644 index b7bd7d0..0000000 --- a/dist/react-native/declarations/presence_state.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default class PresenceState { - stringValue: string; - constructor(state: string); -} diff --git a/dist/react-native/declarations/presence_subscription.d.ts b/dist/react-native/declarations/presence_subscription.d.ts deleted file mode 100644 index 53583cc..0000000 --- a/dist/react-native/declarations/presence_subscription.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import RoomStore from './room_store'; -export interface PresenceSubscriptionOptions { - apiInstance: Instance; - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; -} -export default class PresenceSubscription { - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; - private apiInstance; - constructor(options: PresenceSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - end(): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; -} diff --git a/dist/react-native/declarations/room.d.ts b/dist/react-native/declarations/room.d.ts deleted file mode 100644 index f62e355..0000000 --- a/dist/react-native/declarations/room.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import CursorSubscription from './cursor_subscription'; -import RoomSubscription from './room_subscription'; -import RoomUserStore from './room_user_store'; -export interface RoomOptions { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds?: string[]; -} -export default class Room { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds: string[]; - userStore: RoomUserStore; - subscription?: RoomSubscription; - cursorSubscription?: CursorSubscription; - constructor(options: RoomOptions); - updateWithPropertiesOfRoom(room: Room): void; -} diff --git a/dist/react-native/declarations/room_delegate.d.ts b/dist/react-native/declarations/room_delegate.d.ts deleted file mode 100644 index fbfb142..0000000 --- a/dist/react-native/declarations/room_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Cursor from './cursor'; -import Message from './message'; -import User from './user'; -interface RoomDelegate { - newMessage?: (message: Message) => void; - userStartedTyping?: (user: User) => void; - userStoppedTyping?: (user: User) => void; - userJoined?: (user: User) => void; - userLeft?: (user: User) => void; - userCameOnlineInRoom?: (user: User) => void; - userWentOfflineInRoom?: (user: User) => void; - usersUpdated?: () => void; - error?: (error: any) => void; - cursorSet?: (cursor: Cursor) => void; -} -export default RoomDelegate; diff --git a/dist/react-native/declarations/room_store.d.ts b/dist/react-native/declarations/room_store.d.ts deleted file mode 100644 index 9d9befa..0000000 --- a/dist/react-native/declarations/room_store.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Room from './room'; -export interface RoomStoreOptions { - rooms: Room[]; - apiInstance: Instance; -} -export default class RoomStore { - rooms: Room[]; - apiInstance: Instance; - constructor(options: RoomStoreOptions); - room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - addOrMerge(room: Room): Room; - remove(id: number): Room | undefined; - findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; -} diff --git a/dist/react-native/declarations/room_subscription.d.ts b/dist/react-native/declarations/room_subscription.d.ts deleted file mode 100644 index c37121a..0000000 --- a/dist/react-native/declarations/room_subscription.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicMessageEnricher from './basic_message_enricher'; -import RoomDelegate from './room_delegate'; -export interface RoomSubscriptionOptions { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; -} -export default class RoomSubscription { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; - constructor(options: RoomSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; -} diff --git a/dist/react-native/declarations/room_user_store.d.ts b/dist/react-native/declarations/room_user_store.d.ts deleted file mode 100644 index eb1f60f..0000000 --- a/dist/react-native/declarations/room_user_store.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -import UserStoreCore from './user_store_core'; -export default class RoomUserStore { - private userStoreCore; - constructor(userStoreCore?: UserStoreCore); - addOrMerge(user: User): User; - remove(id: string): User | undefined; -} diff --git a/dist/react-native/declarations/token_provider.d.ts b/dist/react-native/declarations/token_provider.d.ts deleted file mode 100644 index 5fb85e9..0000000 --- a/dist/react-native/declarations/token_provider.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; -export interface TokenProviderAuthContextOptions { - queryParams?: TokenProviderAuthContextQueryParams; - headers?: TokenProviderAuthContextHeaders; -} -export declare type TokenProviderAuthContextHeaders = { - [key: string]: string; -}; -export declare type TokenProviderAuthContextQueryParams = { - [key: string]: string; -}; -export interface TokenProviderOptions { - authContext?: TokenProviderAuthContextOptions; - url: string; -} -export default class TokenProvider implements PlatformTokenProvider { - authContext?: TokenProviderAuthContextOptions; - url: string; - userId?: string; - cachedAccessToken?: string; - cachedTokenExpiresAt?: number; - constructor(options: TokenProviderOptions); - readonly cacheIsStale: boolean; - fetchToken(tokenParams?: any): Promise; - clearToken(token?: string): void; - makeAuthRequest(): Promise; - private cache(accessToken, expiresIn); - private unixTimeNow(); -} diff --git a/dist/react-native/declarations/user.d.ts b/dist/react-native/declarations/user.d.ts deleted file mode 100644 index 7e0b5f4..0000000 --- a/dist/react-native/declarations/user.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import PresencePayload from './presence_payload'; -import PresenceState from './presence_state'; -export interface UserOptions { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; -} -export default class User { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; - presenceState: PresenceState; - lastSeenAt?: string; - constructor(options: UserOptions); - updateWithPropertiesOfUser(user: User): this; - updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; -} diff --git a/dist/react-native/declarations/user_store_core.d.ts b/dist/react-native/declarations/user_store_core.d.ts deleted file mode 100644 index a55ef61..0000000 --- a/dist/react-native/declarations/user_store_core.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -export default class UserStoreCore { - private users; - constructor(users?: User[]); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - find(id: string): User | undefined; -} diff --git a/dist/react-native/declarations/user_subscription.d.ts b/dist/react-native/declarations/user_subscription.d.ts deleted file mode 100644 index 42ea461..0000000 --- a/dist/react-native/declarations/user_subscription.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -export interface UserSubscriptionOptions { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; -} -export default class UserSubscription { - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; - currentUser?: CurrentUser; - private apiInstance; - private filesInstance; - private cursorsInstance; - private typingTimers; - constructor(options: UserSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; - reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; - parseAddedToRoomPayload(eventName: string, data: any): void; - parseRemovedFromRoomPayload(eventName: string, data: any): void; - parseRoomUpdatedPayload(eventName: string, data: any): void; - parseRoomDeletedPayload(eventName: string, data: any): void; - parseUserJoinedPayload(eventName: string, data: any): void; - parseUserLeftPayload(eventName: string, data: any): void; - parseIsTypingPayload(eventName: string, data: any, userId: string): void; - private startedTyping(roomId, userId); - private stoppedTyping(roomId, userId); -} diff --git a/dist/react-native/declarations/utils.d.ts b/dist/react-native/declarations/utils.d.ts deleted file mode 100644 index dbf28ce..0000000 --- a/dist/react-native/declarations/utils.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export declare function urlEncode(data: any): string; -export declare function queryString(data: any): string; -export declare function queryParamsFromFullUrl(url: string): any; -export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; -export declare function allPromisesSettled(promises: Array>): Promise; diff --git a/dist/web/declarations/attachment.d.ts b/dist/web/declarations/attachment.d.ts deleted file mode 100644 index 1e89409..0000000 --- a/dist/web/declarations/attachment.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface Attachment { - fetchRequired: boolean; - link: string; - type: string; -} -export default Attachment; diff --git a/dist/web/declarations/basic_cursor.d.ts b/dist/web/declarations/basic_cursor.d.ts deleted file mode 100644 index 1ab80b5..0000000 --- a/dist/web/declarations/basic_cursor.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface BasicCursor { - cursorType: number; - position: number; - roomId: number; - updatedAt: string; - userId: string; -} -export default BasicCursor; diff --git a/dist/web/declarations/basic_message.d.ts b/dist/web/declarations/basic_message.d.ts deleted file mode 100644 index b28e155..0000000 --- a/dist/web/declarations/basic_message.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Attachment from './attachment'; -interface BasicMessage { - id: number; - senderId: string; - roomId: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; -} -export default BasicMessage; diff --git a/dist/web/declarations/basic_message_enricher.d.ts b/dist/web/declarations/basic_message_enricher.d.ts deleted file mode 100644 index a8f7e15..0000000 --- a/dist/web/declarations/basic_message_enricher.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Logger } from 'pusher-platform'; -import BasicMessage from './basic_message'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import Room from './room'; -import User from './user'; -export interface MessageEnrichmentCompletionHandlers { - onSuccess: (message: Message) => void; - onError: (error: any) => void; -} -export declare type MessageIdsToCompletionHandlers = { - [key: number]: MessageEnrichmentCompletionHandlers; -}; -export declare type UserIdsToBasicMessageIds = { - [key: string]: number[]; -}; -export declare type MessageEnrichmentResult = Message | any; -export declare type MessageIdsToEnrichmentResults = { - [key: number]: MessageEnrichmentResult; -}; -export declare type MessageIdsToBasicMessages = { - [key: number]: BasicMessage; -}; -export default class BasicMessageEnricher { - userStore: GlobalUserStore; - room: Room; - logger: Logger; - private completionOrderList; - private messageIdToCompletionHandlers; - private enrichedMessagesAwaitingCompletionCalls; - private userIdsBeingRetrieved; - private userIdsToBasicMessageIds; - private messagesAwaitingEnrichmentDependentOnUserRetrieval; - constructor(userStore: GlobalUserStore, room: Room, logger: Logger); - enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; - enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; - callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; -} diff --git a/dist/web/declarations/basic_user.d.ts b/dist/web/declarations/basic_user.d.ts deleted file mode 100644 index fb90490..0000000 --- a/dist/web/declarations/basic_user.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface BasicUser { - id: string; - createdAt: string; - updatedAt: string; -} -export default BasicUser; diff --git a/dist/web/declarations/chat_manager.d.ts b/dist/web/declarations/chat_manager.d.ts deleted file mode 100644 index 49a8817..0000000 --- a/dist/web/declarations/chat_manager.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -export interface ChatManagerOptions { - instanceLocator: string; - tokenProvider: TokenProvider; - logger?: Logger; - baseClient?: BaseClient; - userId: string; -} -export default class ChatManager { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userId: string; - private userStore; - private userSubscription; - constructor(options: ChatManagerOptions); - connect(options: ConnectOptions): void; -} -export interface ConnectOptions { - delegate?: ChatManagerDelegate; - onSuccess: (currentUser: CurrentUser) => void; - onError: (error: any) => void; -} diff --git a/dist/web/declarations/chat_manager_delegate.d.ts b/dist/web/declarations/chat_manager_delegate.d.ts deleted file mode 100644 index 5b2d790..0000000 --- a/dist/web/declarations/chat_manager_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Room from './room'; -import User from './user'; -interface ChatManagerDelegate { - addedToRoom?: (room: Room) => void; - removedFromRoom?: (room: Room) => void; - roomUpdated?: (room: Room) => void; - roomDeleted?: (room: Room) => void; - userStartedTyping?: (room: Room, user: User) => void; - userStoppedTyping?: (room: Room, user: User) => void; - userJoinedRoom?: (room: Room, user: User) => void; - userLeftRoom?: (room: Room, user: User) => void; - userCameOnline?: (user: User) => void; - userWentOffline?: (user: User) => void; - error?: (error: any) => void; -} -export default ChatManagerDelegate; diff --git a/dist/web/declarations/constants.d.ts b/dist/web/declarations/constants.d.ts deleted file mode 100644 index d18fd38..0000000 --- a/dist/web/declarations/constants.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare const TYPING_REQ_TTL = 1500; -export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/web/declarations/current_user.d.ts b/dist/web/declarations/current_user.d.ts deleted file mode 100644 index 77a8eae..0000000 --- a/dist/web/declarations/current_user.d.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Instance } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import PresenceSubscription from './presence_subscription'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -import RoomStore from './room_store'; -export interface CreateRoomOptions { - name: string; - private?: boolean; - addUserIds?: string[]; -} -export interface UpdateRoomOptions { - name?: string; - isPrivate?: boolean; -} -export interface FetchRoomMessagesOptions { - initialId?: string; - limit?: number; - direction?: string; -} -export interface CurrentUserOptions { - id: string; - createdAt: string; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - rooms?: Room[]; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; -} -export interface DataAttachment { - file: Blob; - name: string; -} -export interface LinkAttachment { - link: string; - type: string; -} -export declare type GenericAttachment = LinkAttachment | DataAttachment; -export interface AttachmentBody { - resource_link: string; - type: string; -} -export interface SendMessageOptions { - attachment?: GenericAttachment; - roomId: number; - text?: string; -} -export interface CompleteMessageOptions { - attachment?: AttachmentBody; - roomId: number; - text?: string; - user_id: string; -} -export default class CurrentUser { - id: string; - createdAt: string; - cursors: { - [roomId: string]: BasicCursor; - }; - cursorsReq: Promise; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - userStore: GlobalUserStore; - roomStore: RoomStore; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - pathFriendlyId: string; - presenceSubscription: PresenceSubscription; - typingRequestSent: { - [roomId: string]: number; - }; - readonly rooms: Room[]; - constructor(options: CurrentUserOptions); - updateWithPropertiesOf(currentUser: CurrentUser): void; - setupPresenceSubscription(delegate?: ChatManagerDelegate): void; - createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - populateRoomUserStore(room: Room): void; - addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; - deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; - joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; - sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; - subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; - fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; - fetchAttachment(attachmentURL: string): Promise; - private isDataAttachment(attachment); - private isLinkAttachment(attachment); - private uploadFile(file, fileName, roomId); - private sendMessageWithCompleteOptions(options, onSuccess, onError); - private subscribeToCursors(room, roomDelegate); - private getRooms(path, onSuccess, onError); -} diff --git a/dist/web/declarations/cursor.d.ts b/dist/web/declarations/cursor.d.ts deleted file mode 100644 index 3aa3524..0000000 --- a/dist/web/declarations/cursor.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Room from './room'; -import User from './user'; -interface Cursor { - cursorType: number; - position: number; - room: Room; - updatedAt: string; - user: User; -} -export default Cursor; diff --git a/dist/web/declarations/cursor_subscription.d.ts b/dist/web/declarations/cursor_subscription.d.ts deleted file mode 100644 index 08e991b..0000000 --- a/dist/web/declarations/cursor_subscription.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import Cursor from './cursor'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -export interface CursorSubscriptionOptions { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; -} -export default class CursorSubscription { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; - constructor(options: CursorSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; -} diff --git a/dist/web/declarations/cursor_types.d.ts b/dist/web/declarations/cursor_types.d.ts deleted file mode 100644 index 01f22f7..0000000 --- a/dist/web/declarations/cursor_types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare enum CursorType { - Read = 0, -} -export default CursorType; diff --git a/dist/web/declarations/fetched_attachment.d.ts b/dist/web/declarations/fetched_attachment.d.ts deleted file mode 100644 index 907eddc..0000000 --- a/dist/web/declarations/fetched_attachment.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface FetchedAttachmentFile { - bytes: number; - lastModified: number; - name: string; -} -interface FetchedAttachment { - file: FetchedAttachmentFile; - link: string; - ttl: number; -} -export default FetchedAttachment; diff --git a/dist/web/declarations/global_user_store.d.ts b/dist/web/declarations/global_user_store.d.ts deleted file mode 100644 index 7712fe4..0000000 --- a/dist/web/declarations/global_user_store.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import PresencePayload from './presence_payload'; -import User from './user'; -import UserStoreCore from './user_store_core'; -export interface GlobalUserStoreOptions { - apiInstance: Instance; - userStoreCore?: UserStoreCore; -} -export default class GlobalUserStore { - private apiInstance; - private userStoreCore; - constructor(options: GlobalUserStoreOptions); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; - handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; - fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; - initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; -} diff --git a/dist/web/declarations/index.d.ts b/dist/web/declarations/index.d.ts deleted file mode 100644 index 8118af7..0000000 --- a/dist/web/declarations/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BaseClient } from 'pusher-platform'; -import ChatManager from './chat_manager'; -import TokenProvider from './token_provider'; -export { BaseClient, ChatManager, TokenProvider }; -declare const _default: { - BaseClient: typeof BaseClient; - ChatManager: typeof ChatManager; - TokenProvider: typeof TokenProvider; -}; -export default _default; diff --git a/dist/web/declarations/message.d.ts b/dist/web/declarations/message.d.ts deleted file mode 100644 index d7bd58d..0000000 --- a/dist/web/declarations/message.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Attachment from './attachment'; -import Room from './room'; -import User from './user'; -interface Message { - id: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; - sender: User; - room: Room; -} -export default Message; diff --git a/dist/web/declarations/payload_deserializer.d.ts b/dist/web/declarations/payload_deserializer.d.ts deleted file mode 100644 index bb635f2..0000000 --- a/dist/web/declarations/payload_deserializer.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Attachment from './attachment'; -import BasicCursor from './basic_cursor'; -import BasicMessage from './basic_message'; -import BasicUser from './basic_user'; -import CurrentUser from './current_user'; -import FetchedAttachment from './fetched_attachment'; -import GlobalUserStore from './global_user_store'; -import PresencePayload from './presence_payload'; -import Room from './room'; -import User from './user'; -export default class PayloadDeserializer { - static createUserFromPayload(userPayload: any): User; - static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; - static createRoomFromPayload(roomPayload: any): Room; - static createBasicMessageFromPayload(messagePayload: any): BasicMessage; - static createBasicCursorFromPayload(payload: any): BasicCursor; - static createPresencePayloadFromPayload(payload: any): PresencePayload; - static createBasicUserFromPayload(payload: any): BasicUser; - static createAttachmentFromPayload(payload: any): Attachment | undefined; - static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; -} diff --git a/dist/web/declarations/presence_payload.d.ts b/dist/web/declarations/presence_payload.d.ts deleted file mode 100644 index c2a2215..0000000 --- a/dist/web/declarations/presence_payload.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import PresenceState from './presence_state'; -interface PresencePayload { - userId: string; - state: PresenceState; - lastSeenAt?: string; -} -export default PresencePayload; diff --git a/dist/web/declarations/presence_state.d.ts b/dist/web/declarations/presence_state.d.ts deleted file mode 100644 index b7bd7d0..0000000 --- a/dist/web/declarations/presence_state.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default class PresenceState { - stringValue: string; - constructor(state: string); -} diff --git a/dist/web/declarations/presence_subscription.d.ts b/dist/web/declarations/presence_subscription.d.ts deleted file mode 100644 index 53583cc..0000000 --- a/dist/web/declarations/presence_subscription.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import RoomStore from './room_store'; -export interface PresenceSubscriptionOptions { - apiInstance: Instance; - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; -} -export default class PresenceSubscription { - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; - private apiInstance; - constructor(options: PresenceSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - end(): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; -} diff --git a/dist/web/declarations/room.d.ts b/dist/web/declarations/room.d.ts deleted file mode 100644 index f62e355..0000000 --- a/dist/web/declarations/room.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import CursorSubscription from './cursor_subscription'; -import RoomSubscription from './room_subscription'; -import RoomUserStore from './room_user_store'; -export interface RoomOptions { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds?: string[]; -} -export default class Room { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds: string[]; - userStore: RoomUserStore; - subscription?: RoomSubscription; - cursorSubscription?: CursorSubscription; - constructor(options: RoomOptions); - updateWithPropertiesOfRoom(room: Room): void; -} diff --git a/dist/web/declarations/room_delegate.d.ts b/dist/web/declarations/room_delegate.d.ts deleted file mode 100644 index fbfb142..0000000 --- a/dist/web/declarations/room_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Cursor from './cursor'; -import Message from './message'; -import User from './user'; -interface RoomDelegate { - newMessage?: (message: Message) => void; - userStartedTyping?: (user: User) => void; - userStoppedTyping?: (user: User) => void; - userJoined?: (user: User) => void; - userLeft?: (user: User) => void; - userCameOnlineInRoom?: (user: User) => void; - userWentOfflineInRoom?: (user: User) => void; - usersUpdated?: () => void; - error?: (error: any) => void; - cursorSet?: (cursor: Cursor) => void; -} -export default RoomDelegate; diff --git a/dist/web/declarations/room_store.d.ts b/dist/web/declarations/room_store.d.ts deleted file mode 100644 index 9d9befa..0000000 --- a/dist/web/declarations/room_store.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Room from './room'; -export interface RoomStoreOptions { - rooms: Room[]; - apiInstance: Instance; -} -export default class RoomStore { - rooms: Room[]; - apiInstance: Instance; - constructor(options: RoomStoreOptions); - room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - addOrMerge(room: Room): Room; - remove(id: number): Room | undefined; - findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; -} diff --git a/dist/web/declarations/room_subscription.d.ts b/dist/web/declarations/room_subscription.d.ts deleted file mode 100644 index c37121a..0000000 --- a/dist/web/declarations/room_subscription.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicMessageEnricher from './basic_message_enricher'; -import RoomDelegate from './room_delegate'; -export interface RoomSubscriptionOptions { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; -} -export default class RoomSubscription { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; - constructor(options: RoomSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; -} diff --git a/dist/web/declarations/room_user_store.d.ts b/dist/web/declarations/room_user_store.d.ts deleted file mode 100644 index eb1f60f..0000000 --- a/dist/web/declarations/room_user_store.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -import UserStoreCore from './user_store_core'; -export default class RoomUserStore { - private userStoreCore; - constructor(userStoreCore?: UserStoreCore); - addOrMerge(user: User): User; - remove(id: string): User | undefined; -} diff --git a/dist/web/declarations/token_provider.d.ts b/dist/web/declarations/token_provider.d.ts deleted file mode 100644 index 5fb85e9..0000000 --- a/dist/web/declarations/token_provider.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; -export interface TokenProviderAuthContextOptions { - queryParams?: TokenProviderAuthContextQueryParams; - headers?: TokenProviderAuthContextHeaders; -} -export declare type TokenProviderAuthContextHeaders = { - [key: string]: string; -}; -export declare type TokenProviderAuthContextQueryParams = { - [key: string]: string; -}; -export interface TokenProviderOptions { - authContext?: TokenProviderAuthContextOptions; - url: string; -} -export default class TokenProvider implements PlatformTokenProvider { - authContext?: TokenProviderAuthContextOptions; - url: string; - userId?: string; - cachedAccessToken?: string; - cachedTokenExpiresAt?: number; - constructor(options: TokenProviderOptions); - readonly cacheIsStale: boolean; - fetchToken(tokenParams?: any): Promise; - clearToken(token?: string): void; - makeAuthRequest(): Promise; - private cache(accessToken, expiresIn); - private unixTimeNow(); -} diff --git a/dist/web/declarations/user.d.ts b/dist/web/declarations/user.d.ts deleted file mode 100644 index 7e0b5f4..0000000 --- a/dist/web/declarations/user.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import PresencePayload from './presence_payload'; -import PresenceState from './presence_state'; -export interface UserOptions { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; -} -export default class User { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; - presenceState: PresenceState; - lastSeenAt?: string; - constructor(options: UserOptions); - updateWithPropertiesOfUser(user: User): this; - updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; -} diff --git a/dist/web/declarations/user_store_core.d.ts b/dist/web/declarations/user_store_core.d.ts deleted file mode 100644 index a55ef61..0000000 --- a/dist/web/declarations/user_store_core.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -export default class UserStoreCore { - private users; - constructor(users?: User[]); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - find(id: string): User | undefined; -} diff --git a/dist/web/declarations/user_subscription.d.ts b/dist/web/declarations/user_subscription.d.ts deleted file mode 100644 index 42ea461..0000000 --- a/dist/web/declarations/user_subscription.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -export interface UserSubscriptionOptions { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; -} -export default class UserSubscription { - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; - currentUser?: CurrentUser; - private apiInstance; - private filesInstance; - private cursorsInstance; - private typingTimers; - constructor(options: UserSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; - reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; - parseAddedToRoomPayload(eventName: string, data: any): void; - parseRemovedFromRoomPayload(eventName: string, data: any): void; - parseRoomUpdatedPayload(eventName: string, data: any): void; - parseRoomDeletedPayload(eventName: string, data: any): void; - parseUserJoinedPayload(eventName: string, data: any): void; - parseUserLeftPayload(eventName: string, data: any): void; - parseIsTypingPayload(eventName: string, data: any, userId: string): void; - private startedTyping(roomId, userId); - private stoppedTyping(roomId, userId); -} diff --git a/dist/web/declarations/utils.d.ts b/dist/web/declarations/utils.d.ts deleted file mode 100644 index dbf28ce..0000000 --- a/dist/web/declarations/utils.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export declare function urlEncode(data: any): string; -export declare function queryString(data: any): string; -export declare function queryParamsFromFullUrl(url: string): any; -export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; -export declare function allPromisesSettled(promises: Array>): Promise; diff --git a/dist/worker/chatkit.worker.js b/dist/worker/chatkit.worker.js deleted file mode 100644 index 8efc579..0000000 --- a/dist/worker/chatkit.worker.js +++ /dev/null @@ -1,3982 +0,0 @@ -var Chatkit = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 7); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var current_user_1 = __webpack_require__(11); -var presence_state_1 = __webpack_require__(4); -var room_1 = __webpack_require__(18); -var user_1 = __webpack_require__(20); -var utils_1 = __webpack_require__(1); -var checkPresenceAndTypeOfFieldsInPayload = function (requiredFieldsWithTypes, payload) { - Object.keys(requiredFieldsWithTypes).forEach(function (key) { - if (payload[key] === undefined) { - throw new Error("Payload missing key: " + key); - } - var receivedType = typeof payload[key]; - var expectedType = requiredFieldsWithTypes[key]; - if (receivedType !== expectedType) { - throw new Error("Value for key: " + key + " in payload was " + receivedType + ", expected " + expectedType); - } - }); -}; -var PayloadDeserializer = (function () { - function PayloadDeserializer() { - } - PayloadDeserializer.createUserFromPayload = function (userPayload) { - var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); - return new user_1.default({ - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - customData: userPayload.custom_data, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - }); - }; - PayloadDeserializer.createCurrentUserFromPayload = function (userPayload, apiInstance, filesInstance, cursorsInstance, userStore) { - var basicUser = PayloadDeserializer.createBasicUserFromPayload(userPayload); - return new current_user_1.default({ - apiInstance: apiInstance, - avatarURL: userPayload.avatar_url, - createdAt: basicUser.createdAt, - cursorsInstance: cursorsInstance, - customData: userPayload.custom_data, - filesInstance: filesInstance, - id: basicUser.id, - name: userPayload.name, - updatedAt: basicUser.updatedAt, - userStore: userStore, - }); - }; - PayloadDeserializer.createRoomFromPayload = function (roomPayload) { - var requiredFieldsWithTypes = { - created_at: 'string', - created_by_id: 'string', - id: 'number', - name: 'string', - private: 'boolean', - updated_at: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, roomPayload); - var memberUserIds = []; - if (roomPayload.member_user_ids) { - memberUserIds = roomPayload.member_user_ids; - } - return new room_1.default({ - createdAt: roomPayload.created_at, - createdByUserId: roomPayload.created_by_id, - deletedAt: roomPayload.deleted_at, - id: roomPayload.id, - isPrivate: roomPayload.private, - name: roomPayload.name, - updatedAt: roomPayload.updated_at, - userIds: memberUserIds, - }); - }; - PayloadDeserializer.createBasicMessageFromPayload = function (messagePayload) { - var requiredFieldsWithTypes = { - created_at: 'string', - id: 'number', - room_id: 'number', - text: 'string', - updated_at: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, messagePayload); - var attachment = this.createAttachmentFromPayload(messagePayload.attachment); - return { - attachment: attachment, - createdAt: messagePayload.created_at, - id: messagePayload.id, - roomId: messagePayload.room_id, - senderId: messagePayload.user_id, - text: messagePayload.text, - updatedAt: messagePayload.updated_at, - }; - }; - PayloadDeserializer.createBasicCursorFromPayload = function (payload) { - var requiredFieldsWithTypes = { - cursor_type: 'number', - position: 'number', - room_id: 'number', - updated_at: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - return { - cursorType: payload.cursor_type, - position: payload.position, - roomId: payload.room_id, - updatedAt: payload.updated_at, - userId: payload.user_id, - }; - }; - PayloadDeserializer.createPresencePayloadFromPayload = function (payload) { - var requiredFieldsWithTypes = { - state: 'string', - user_id: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var state = new presence_state_1.default(payload.state); - return { - lastSeenAt: payload.last_seen_at, - state: state, - userId: payload.user_id, - }; - }; - PayloadDeserializer.createBasicUserFromPayload = function (payload) { - var requiredFieldsWithTypes = { - created_at: 'string', - id: 'string', - updated_at: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - return { - createdAt: payload.created_at, - id: payload.id, - updatedAt: payload.updated_at, - }; - }; - PayloadDeserializer.createAttachmentFromPayload = function (payload) { - if (payload === undefined) { - return undefined; - } - var requiredFieldsWithTypes = { - resource_link: 'string', - type: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var linkQueryParams = utils_1.queryParamsFromFullUrl(payload.resource_link); - var fetchRequired = linkQueryParams.chatkit_link !== undefined && - linkQueryParams.chatkit_link === 'true'; - return { - fetchRequired: fetchRequired, - link: payload.resource_link, - type: payload.type, - }; - }; - PayloadDeserializer.createFetchedAttachmentFromPayload = function (payload) { - if (payload === undefined) { - return undefined; - } - var requiredFieldsWithTypes = { - file: 'object', - resource_link: 'string', - ttl: 'number', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypes, payload); - var requiredFieldsWithTypesForFileField = { - bytes: 'number', - last_modified: 'number', - name: 'string', - }; - checkPresenceAndTypeOfFieldsInPayload(requiredFieldsWithTypesForFileField, payload.file); - var file = payload.file; - var bytes = file.bytes, name = file.name; - return { - file: { - bytes: bytes, - lastModified: file.last_modified, - name: name, - }, - link: payload.resource_link, - ttl: payload.ttl, - }; - }; - return PayloadDeserializer; -}()); -exports.default = PayloadDeserializer; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function urlEncode(data) { - return Object.keys(data) - .filter(function (key) { return data[key] !== undefined; }) - .map(function (key) { return key + "=" + encodeURIComponent(data[key]); }) - .join('&'); -} -exports.urlEncode = urlEncode; -function queryString(data) { - var encodedData = urlEncode(data); - return encodedData ? "?" + encodedData : ''; -} -exports.queryString = queryString; -function queryParamsFromFullUrl(url) { - if (url.indexOf('?') === -1) { - return {}; - } - var splitUrl = url.split('?'); - var queryStr = splitUrl.slice(1).join('&'); - return queryParamObject(queryStr); -} -exports.queryParamsFromFullUrl = queryParamsFromFullUrl; -function querylessUrlAndQueryObjectFromFullUrl(urlString) { - if (urlString.indexOf('?') === -1) { - return { - queryObject: {}, - querylessUrl: urlString, - }; - } - var splitUrl = urlString.split('?'); - var querylessUrl = splitUrl[0]; - var queryStr = splitUrl.slice(1).join('&'); - return { - queryObject: queryParamObject(queryStr), - querylessUrl: querylessUrl, - }; -} -function queryParamObject(queryParamString) { - return queryParamString - .split('&') - .map(function (str) { - var _a = str.split('='), key = _a[0], value = _a[1]; - return _b = {}, _b[key] = decodeURI(value), _b; - var _b; - }) - .reduce(function (prev, curr) { return Object.assign(prev, curr); }); -} -function mergeQueryParamsIntoUrl(urlString, queryParams) { - var _a = querylessUrlAndQueryObjectFromFullUrl(urlString), querylessUrl = _a.querylessUrl, queryObject = _a.queryObject; - var fullQueryString = queryString(Object.assign(queryObject, queryParams)); - return "" + querylessUrl + fullQueryString; -} -exports.mergeQueryParamsIntoUrl = mergeQueryParamsIntoUrl; -function allPromisesSettled(promises) { - return Promise.all(promises.map(function (p) { - return Promise.resolve(p).then(function (v) { return ({ - state: 'fulfilled', - value: v, - }); }, function (r) { return ({ - reason: r, - state: 'rejected', - }); }); - })); -} -exports.allPromisesSettled = allPromisesSettled; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(8); - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.TYPING_REQ_TTL = 1500; -exports.TYPING_REQ_LEEWAY = 500; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var PresenceState = (function () { - function PresenceState(state) { - switch (state) { - case 'online': - this.stringValue = state; - break; - case 'offline': - this.stringValue = state; - break; - default: - this.stringValue = 'unknown'; - break; - } - } - return PresenceState; -}()); -exports.default = PresenceState; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var UserStoreCore = (function () { - function UserStoreCore(users) { - if (users === void 0) { users = new Array(); } - this.users = users; - } - UserStoreCore.prototype.addOrMerge = function (user) { - var existingUser = this.users.find(function (el) { return el.id === user.id; }); - if (existingUser) { - existingUser.updateWithPropertiesOfUser(user); - return existingUser; - } - else { - this.users.push(user); - return user; - } - }; - UserStoreCore.prototype.remove = function (id) { - var indexOfUser = this.users.findIndex(function (el) { return el.id === id; }); - if (indexOfUser === -1) { - return undefined; - } - var user = this.users[indexOfUser]; - this.users.splice(indexOfUser, 1); - return user; - }; - UserStoreCore.prototype.find = function (id) { - return this.users.find(function (el) { return el.id === id; }); - }; - return UserStoreCore; -}()); -exports.default = UserStoreCore; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var utils_1 = __webpack_require__(1); -var TokenProvider = (function () { - function TokenProvider(options) { - this.authContext = options.authContext || {}; - this.url = options.url; - } - Object.defineProperty(TokenProvider.prototype, "cacheIsStale", { - get: function () { - if (this.cachedAccessToken && this.cachedTokenExpiresAt) { - return this.unixTimeNow() > this.cachedTokenExpiresAt; - } - return true; - }, - enumerable: true, - configurable: true - }); - TokenProvider.prototype.fetchToken = function (tokenParams) { - var _this = this; - if (this.cacheIsStale) { - return this.makeAuthRequest().then(function (responseBody) { - var access_token = responseBody.access_token, expires_in = responseBody.expires_in; - _this.cache(access_token, expires_in); - return access_token; - }); - } - return new Promise(function (resolve, reject) { - resolve(_this.cachedAccessToken); - }); - }; - TokenProvider.prototype.clearToken = function (token) { - this.cachedAccessToken = undefined; - this.cachedTokenExpiresAt = undefined; - }; - TokenProvider.prototype.makeAuthRequest = function () { - var url; - var authRequestQueryParams = (this.authContext || {}).queryParams || {}; - if (this.userId === undefined) { - url = utils_1.mergeQueryParamsIntoUrl(this.url, authRequestQueryParams); - } - else { - var authContextWithUserId = __assign({ user_id: this.userId }, authRequestQueryParams); - url = utils_1.mergeQueryParamsIntoUrl(this.url, authContextWithUserId); - } - var authRequestHeaders = (this.authContext || {}).headers || {}; - var headers = __assign((_a = {}, _a['Content-Type'] = 'application/x-www-form-urlencoded', _a), authRequestHeaders); - var body = utils_1.urlEncode({ grant_type: 'client_credentials' }); - return pusher_platform_1.sendRawRequest({ - body: body, - headers: headers, - method: 'POST', - url: url, - }).then(function (res) { - return JSON.parse(res); - }); - var _a; - }; - TokenProvider.prototype.cache = function (accessToken, expiresIn) { - this.cachedAccessToken = accessToken; - this.cachedTokenExpiresAt = this.unixTimeNow() + expiresIn; - }; - TokenProvider.prototype.unixTimeNow = function () { - return Math.floor(Date.now() / 1000); - }; - return TokenProvider; -}()); -exports.default = TokenProvider; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -exports.BaseClient = pusher_platform_1.BaseClient; -var chat_manager_1 = __webpack_require__(9); -exports.ChatManager = chat_manager_1.default; -var token_provider_1 = __webpack_require__(6); -exports.TokenProvider = token_provider_1.default; -exports.default = { - BaseClient: pusher_platform_1.BaseClient, - ChatManager: chat_manager_1.default, - TokenProvider: token_provider_1.default, -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -var PusherPlatform = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function responseToHeadersObject(headerStr) { - var headers = {}; - if (!headerStr) { - return headers; - } - var headerPairs = headerStr.split('\u000d\u000a'); - for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { - var headerPair = headerPairs_1[_i]; - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - return headers; -} -exports.responseToHeadersObject = responseToHeadersObject; -var ErrorResponse = (function () { - function ErrorResponse(statusCode, headers, info) { - this.statusCode = statusCode; - this.headers = headers; - this.info = info; - } - ErrorResponse.fromXHR = function (xhr) { - var errorInfo = xhr.responseText; - try { - errorInfo = JSON.parse(xhr.responseText); - } - catch (e) { - } - return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); - }; - return ErrorResponse; -}()); -exports.ErrorResponse = ErrorResponse; -var NetworkError = (function () { - function NetworkError(error) { - this.error = error; - } - return NetworkError; -}()); -exports.NetworkError = NetworkError; -var XhrReadyState; -(function (XhrReadyState) { - XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; - XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; - XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; - XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; - XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; -})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var LogLevel; -(function (LogLevel) { - LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; - LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; - LogLevel[LogLevel["INFO"] = 3] = "INFO"; - LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; - LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; -})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); -var ConsoleLogger = (function () { - function ConsoleLogger(threshold) { - if (threshold === void 0) { threshold = 2; } - this.threshold = threshold; - var groups = Array(); - var hr = '--------------------------------------------------------------------------------'; - if (!self.console.group) { - self.console.group = function (label) { - groups.push(label); - self.console.log('%c \nBEGIN GROUP: %c', hr, label); - }; - } - if (!self.console.groupEnd) { - self.console.groupEnd = function () { - self.console.log('END GROUP: %c\n%c', groups.pop(), hr); - }; - } - } - ConsoleLogger.prototype.verbose = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(self.console.log, LogLevel.VERBOSE, items); - }; - ConsoleLogger.prototype.debug = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(self.console.log, LogLevel.DEBUG, items); - }; - ConsoleLogger.prototype.info = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(self.console.info, LogLevel.INFO, items); - }; - ConsoleLogger.prototype.warn = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(self.console.warn, LogLevel.WARNING, items); - }; - ConsoleLogger.prototype.error = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(self.console.error, LogLevel.ERROR, items); - }; - ConsoleLogger.prototype.log = function (logFunction, level, items) { - var _this = this; - if (level >= this.threshold) { - var loggerSignature_1 = "Logger." + LogLevel[level]; - if (items.length > 1) { - self.console.group(); - items.forEach(function (item) { - _this.errorAwareLog(logFunction, item, loggerSignature_1); - }); - self.console.groupEnd(); - } - else { - this.errorAwareLog(logFunction, items[0], loggerSignature_1); - } - } - }; - ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { - if (item.info && item.info.error_uri) { - var errorDesc = item.info.error_description; - var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; - logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); - } - else { - logFunction(loggerSignature + ": ", item); - } - }; - return ConsoleLogger; -}()); -exports.ConsoleLogger = ConsoleLogger; -var EmptyLogger = (function () { - function EmptyLogger() { - } - EmptyLogger.prototype.verbose = function (message, error) { }; - EmptyLogger.prototype.debug = function (message, error) { }; - EmptyLogger.prototype.info = function (message, error) { }; - EmptyLogger.prototype.warn = function (message, error) { }; - EmptyLogger.prototype.error = function (message, error) { }; - return EmptyLogger; -}()); -exports.EmptyLogger = EmptyLogger; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createRetryStrategyOptionsOrDefault = function (options) { - var initialTimeoutMillis = options.initialTimeoutMillis || 1000; - var maxTimeoutMillis = options.maxTimeoutMillis || 5000; - var limit = -1; - if (options.limit !== undefined && options.limit != null) { - limit = options.limit; - } - var increaseTimeout; - if (options.increaseTimeout !== undefined) { - increaseTimeout = options.increaseTimeout; - } - else { - increaseTimeout = function (currentTimeout) { - if (currentTimeout * 2 > maxTimeoutMillis) { - return maxTimeoutMillis; - } - else { - return currentTimeout * 2; - } - }; - } - return { - increaseTimeout: increaseTimeout, - initialTimeoutMillis: initialTimeoutMillis, - limit: limit, - maxTimeoutMillis: maxTimeoutMillis, - }; -}; -var Retry = (function () { - function Retry(waitTimeMillis) { - this.waitTimeMillis = waitTimeMillis; - } - return Retry; -}()); -exports.Retry = Retry; -var DoNotRetry = (function () { - function DoNotRetry(error) { - this.error = error; - } - return DoNotRetry; -}()); -exports.DoNotRetry = DoNotRetry; -var requestMethodIsSafe = function (method) { - method = method.toUpperCase(); - return (method === 'GET' || - method === 'HEAD' || - method === 'OPTIONS' || - method === 'SUBSCRIBE'); -}; -var RetryResolution = (function () { - function RetryResolution(options, logger, retryUnsafeRequests) { - this.options = options; - this.logger = logger; - this.retryUnsafeRequests = retryUnsafeRequests; - this.currentRetryCount = 0; - this.initialTimeoutMillis = options.initialTimeoutMillis; - this.maxTimeoutMillis = options.maxTimeoutMillis; - this.limit = options.limit; - this.increaseTimeoutFunction = options.increaseTimeout; - this.currentBackoffMillis = this.initialTimeoutMillis; - } - RetryResolution.prototype.attemptRetry = function (error) { - this.logger.verbose(this.constructor.name + ": Error received", error); - if (this.currentRetryCount >= this.limit && this.limit >= 0) { - this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); - return new DoNotRetry(error); - } - if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { - this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); - return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); - } - if (error instanceof network_1.NetworkError || - (error instanceof network_1.ErrorResponse && - requestMethodIsSafe(error.headers['Request-Method'])) || - this.retryUnsafeRequests) { - return this.shouldSafeRetry(error); - } - if (error instanceof network_1.NetworkError) { - return this.shouldSafeRetry(error); - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.shouldSafeRetry = function (error) { - if (error instanceof network_1.NetworkError) { - this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); - return new Retry(this.calulateMillisToRetry()); - } - else if (error instanceof network_1.ErrorResponse) { - if (error.statusCode >= 500 && error.statusCode < 600) { - this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); - return new Retry(this.calulateMillisToRetry()); - } - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.calulateMillisToRetry = function () { - this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); - this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); - return this.currentBackoffMillis; - }; - return RetryResolution; -}()); -exports.RetryResolution = RetryResolution; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var logger_1 = __webpack_require__(1); -var request_1 = __webpack_require__(4); -var resuming_subscription_1 = __webpack_require__(5); -var retrying_subscription_1 = __webpack_require__(6); -var subscribe_strategy_1 = __webpack_require__(11); -var subscription_1 = __webpack_require__(12); -var token_providing_subscription_1 = __webpack_require__(7); -var http_1 = __webpack_require__(13); -var websocket_1 = __webpack_require__(14); -var transports_1 = __webpack_require__(8); -var BaseClient = (function () { - function BaseClient(options) { - this.options = options; - this.host = options.host.replace(/(\/)+$/, ''); - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.websocketTransport = new websocket_1.default(this.host); - this.httpTransport = new http_1.default(this.host, options.encrypted); - } - BaseClient.prototype.request = function (options, tokenParams) { - var _this = this; - if (options.tokenProvider) { - return options.tokenProvider - .fetchToken(tokenParams) - .then(function (token) { - if (options.headers !== undefined) { - options.headers['Authorization'] = "Bearer " + token; - } - else { - options.headers = (_a = {}, - _a['Authorization'] = "Bearer " + token, - _a); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - var _a; - }) - .catch(function (error) { - _this.logger.error(error); - }); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - }; - BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - return BaseClient; -}()); -exports.BaseClient = BaseClient; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -function executeNetworkRequest(createXhr, options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); - sendBody(xhr, options); - }); -} -exports.executeNetworkRequest = executeNetworkRequest; -function sendBody(xhr, options) { - if (options.json) { - xhr.send(JSON.stringify(options.json)); - } - else { - xhr.send(options.body); - } -} -function sendRawRequest(options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(new self.XMLHttpRequest(), resolve, reject); - xhr.open(options.method.toUpperCase(), options.url, true); - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - xhr.send(options.body); - }); -} -exports.sendRawRequest = sendRawRequest; -function attachOnReadyStateChangeHandler(xhr, resolve, reject) { - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status >= 200 && xhr.status < 300) { - resolve(xhr.response); - } - else if (xhr.status !== 0) { - reject(network_1.ErrorResponse.fromXHR(xhr)); - } - else { - reject(new network_1.NetworkError('No Connection')); - } - } - }; - return xhr; -} - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { - var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); - var ResumingSubscription = (function () { - function ResumingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - this.onTransition = onTransition; - var lastEventId = initialEventId; - logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); - if (lastEventId) { - headers['Last-Event-Id'] = lastEventId; - logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); - } - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpeningSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpenSubscriptionState; - }()); - var ResumingSubscriptionState = (function () { - function ResumingSubscriptionState(error, onTransition, lastEventId) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); - var executeSubscriptionOnce = function (error, lastEventId) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = self.setTimeout(function () { - executeNextSubscribeStrategy(lastEventId); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function (lastEventId) { - logger.verbose("ResumingSubscription: trying to re-establish the subscription"); - if (lastEventId) { - logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); - headers['Last-Event-Id'] = lastEventId; - } - _this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - executeSubscriptionOnce(error, lastEventId); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error, lastEventId); - } - ResumingSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - self.clearTimeout(this.timeout); - this.underlyingSubscription.unsubscribe(); - }; - return ResumingSubscriptionState; - }()); - var EndingSubscriptionState = (function () { - function EndingSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); - } - EndingSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription is already ending'); - }; - return EndingSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return ResumingSubscription; - }()); - return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { - var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); - var RetryingSubscription = (function () { - function RetryingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { - return onTransition(new RetryingSubscriptionState(error, onTransition)); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - throw new Error('Method not implemented.'); - }; - return OpeningSubscriptionState; - }()); - var RetryingSubscriptionState = (function () { - function RetryingSubscriptionState(error, onTransition) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); - var executeSubscriptionOnce = function (error) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = self.setTimeout(function () { - executeNextSubscribeStrategy(); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function () { - logger.verbose("RetryingSubscription: trying to re-establish the subscription"); - var underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { return executeSubscriptionOnce(error); }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error); - } - RetryingSubscriptionState.prototype.unsubscribe = function () { - self.clearTimeout(this.timeout); - this.onTransition(new EndedSubscriptionState()); - }; - return RetryingSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - this.onTransition(new EndedSubscriptionState()); - }; - return OpenSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return RetryingSubscription; - }()); - return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { - if (tokenProvider) { - return function (listeners, headers) { - return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); - }; - } - return nextSubscribeStrategy; -}; -var TokenProvidingSubscription = (function () { - function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { - var _this = this; - this.logger = logger; - this.listeners = listeners; - this.headers = headers; - this.tokenProvider = tokenProvider; - this.nextSubscribeStrategy = nextSubscribeStrategy; - this.unsubscribe = function () { - _this.state.unsubscribe(); - _this.state = new InactiveState(_this.logger); - }; - this.state = new ActiveState(logger, headers, nextSubscribeStrategy); - this.subscribe(); - } - TokenProvidingSubscription.prototype.subscribe = function () { - var _this = this; - this.tokenProvider - .fetchToken() - .then(function (token) { - var existingListeners = Object.assign({}, _this.listeners); - _this.state.subscribe(token, { - onEnd: function (error) { - _this.state = new InactiveState(_this.logger); - existingListeners.onEnd(error); - }, - onError: function (error) { - if (_this.isTokenExpiredError(error)) { - _this.tokenProvider.clearToken(token); - _this.subscribe(); - } - else { - _this.state = new InactiveState(_this.logger); - existingListeners.onError(error); - } - }, - onEvent: _this.listeners.onEvent, - onOpen: _this.listeners.onOpen, - }); - }) - .catch(function (error) { - _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); - _this.state = new InactiveState(_this.logger); - _this.listeners.onError(error); - }); - }; - TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { - return (error instanceof network_1.ErrorResponse && - error.statusCode === 401 && - error.info === 'authentication/expired'); - }; - return TokenProvidingSubscription; -}()); -var ActiveState = (function () { - function ActiveState(logger, headers, nextSubscribeStrategy) { - this.logger = logger; - this.headers = headers; - this.nextSubscribeStrategy = nextSubscribeStrategy; - logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); - } - ActiveState.prototype.subscribe = function (token, listeners) { - var _this = this; - this.putTokenIntoHeader(token); - this.underlyingSubscription = this.nextSubscribeStrategy({ - onEnd: function (error) { - _this.logger.verbose("TokenProvidingSubscription: subscription ended"); - listeners.onEnd(error); - }, - onError: function (error) { - _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); - listeners.onError(error); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - _this.logger.verbose("TokenProvidingSubscription: subscription opened"); - listeners.onOpen(headers); - }, - onRetrying: listeners.onRetrying, - }, this.headers); - }; - ActiveState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - }; - ActiveState.prototype.putTokenIntoHeader = function (token) { - this.headers['Authorization'] = "Bearer " + token; - this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); - }; - return ActiveState; -}()); -var InactiveState = (function () { - function InactiveState(logger) { - this.logger = logger; - logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); - } - InactiveState.prototype.subscribe = function (token, listeners) { - this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); - }; - InactiveState.prototype.unsubscribe = function () { - this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); - }; - return InactiveState; -}()); - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createTransportStrategy = function (path, transport, logger) { - return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HOST_BASE = 'pusherplatform.io'; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -exports.BaseClient = base_client_1.BaseClient; -var host_base_1 = __webpack_require__(9); -exports.HOST_BASE = host_base_1.HOST_BASE; -var instance_1 = __webpack_require__(15); -exports.Instance = instance_1.default; -var logger_1 = __webpack_require__(1); -exports.ConsoleLogger = logger_1.ConsoleLogger; -exports.EmptyLogger = logger_1.EmptyLogger; -var network_1 = __webpack_require__(0); -exports.ErrorResponse = network_1.ErrorResponse; -exports.NetworkError = network_1.NetworkError; -exports.responseToHeadersObject = network_1.responseToHeadersObject; -exports.XhrReadyState = network_1.XhrReadyState; -var request_1 = __webpack_require__(4); -exports.executeNetworkRequest = request_1.executeNetworkRequest; -exports.sendRawRequest = request_1.sendRawRequest; -var resuming_subscription_1 = __webpack_require__(5); -exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; -exports.DoNotRetry = retry_strategy_1.DoNotRetry; -exports.Retry = retry_strategy_1.Retry; -exports.RetryResolution = retry_strategy_1.RetryResolution; -var retrying_subscription_1 = __webpack_require__(6); -exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; -var token_providing_subscription_1 = __webpack_require__(7); -exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; -var transports_1 = __webpack_require__(8); -exports.createTransportStrategy = transports_1.createTransportStrategy; -exports.default = { - BaseClient: base_client_1.BaseClient, - ConsoleLogger: logger_1.ConsoleLogger, - EmptyLogger: logger_1.EmptyLogger, - Instance: instance_1.default, -}; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { - return { - onEnd: subListeners.onEnd, - onError: subListeners.onError, - onEvent: subListeners.onEvent, - onOpen: subListeners.onOpen, - onRetrying: subListeners.onRetrying, - }; -}; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.replaceMissingListenersWithNoOps = function (listeners) { - var onEndNoOp = function (error) { }; - var onEnd = listeners.onEnd || onEndNoOp; - var onErrorNoOp = function (error) { }; - var onError = listeners.onError || onErrorNoOp; - var onEventNoOp = function (event) { }; - var onEvent = listeners.onEvent || onEventNoOp; - var onOpenNoOp = function (headers) { }; - var onOpen = listeners.onOpen || onOpenNoOp; - var onRetryingNoOp = function () { }; - var onRetrying = listeners.onRetrying || onRetryingNoOp; - var onSubscribeNoOp = function () { }; - var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; - return { - onEnd: onEnd, - onError: onError, - onEvent: onEvent, - onOpen: onOpen, - onRetrying: onRetrying, - onSubscribe: onSubscribe, - }; -}; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var HttpTransportState; -(function (HttpTransportState) { - HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; - HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; - HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; - HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; - HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; -})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); -var HttpSubscription = (function () { - function HttpSubscription(xhr, listeners) { - var _this = this; - this.gotEOS = false; - this.lastNewlineIndex = 0; - this.state = HttpTransportState.UNOPENED; - this.xhr = xhr; - this.listeners = listeners; - this.xhr.onreadystatechange = function () { - switch (_this.xhr.readyState) { - case network_1.XhrReadyState.UNSENT: - case network_1.XhrReadyState.OPENED: - case network_1.XhrReadyState.HEADERS_RECEIVED: - _this.assertStateIsIn(HttpTransportState.OPENING); - break; - case network_1.XhrReadyState.LOADING: - _this.onLoading(); - break; - case network_1.XhrReadyState.DONE: - _this.onDone(); - break; - } - }; - this.state = HttpTransportState.OPENING; - this.xhr.send(); - return this; - } - HttpSubscription.prototype.unsubscribe = function () { - this.state = HttpTransportState.ENDED; - this.xhr.abort(); - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - }; - HttpSubscription.prototype.onLoading = function () { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - self.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN); - var err = this.onChunk(); - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - if (err) { - this.state = HttpTransportState.ENDED; - if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else { - } - } - }; - HttpSubscription.prototype.onDone = function () { - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - var err = this.onChunk(); - if (err) { - this.state = HttpTransportState.ENDED; - if (err.statusCode === 204) { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else if (this.state <= HttpTransportState.ENDING) { - if (this.listeners.onError) { - this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); - } - } - else { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - } - else { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); - if (this.state === HttpTransportState.ENDED) { - return; - } - else if (this.xhr.status === 0) { - if (this.listeners.onError) { - this.listeners.onError(new network_1.NetworkError('Connection lost.')); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); - } - } - } - }; - HttpSubscription.prototype.onChunk = function () { - this.assertStateIsIn(HttpTransportState.OPEN); - var response = this.xhr.responseText; - var newlineIndex = response.lastIndexOf('\n'); - if (newlineIndex > this.lastNewlineIndex) { - var rawEvents = response - .slice(this.lastNewlineIndex, newlineIndex) - .split('\n'); - this.lastNewlineIndex = newlineIndex; - for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { - var rawEvent = rawEvents_1[_i]; - if (rawEvent.length === 0) { - continue; - } - var data = JSON.parse(rawEvent); - var err = this.onMessage(data); - if (err != null) { - return err; - } - } - } - }; - HttpSubscription.prototype.assertStateIsIn = function () { - var _this = this; - var validStates = []; - for (var _i = 0; _i < arguments.length; _i++) { - validStates[_i] = arguments[_i]; - } - var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); - if (!stateIsValid) { - var expectedStates = validStates - .map(function (state) { return HttpTransportState[state]; }) - .join(', '); - var actualState = HttpTransportState[this.state]; - self.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); - } - }; - HttpSubscription.prototype.onMessage = function (message) { - this.assertStateIsIn(HttpTransportState.OPEN); - this.verifyMessage(message); - switch (message[0]) { - case 0: - return null; - case 1: - return this.onEventMessage(message); - case 255: - return this.onEOSMessage(message); - default: - return new Error('Unknown Message: ' + JSON.stringify(message)); - } - }; - HttpSubscription.prototype.onEventMessage = function (eventMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eventMessage.length !== 4) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; - if (typeof id !== 'string') { - return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); - } - if (this.listeners.onEvent) { - this.listeners.onEvent({ body: body, headers: headers, eventId: id }); - } - return null; - }; - HttpSubscription.prototype.onEOSMessage = function (eosMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eosMessage.length !== 4) { - return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); - } - var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; - if (typeof statusCode !== 'number') { - return new Error('Invalid EOS Status Code'); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid EOS ElementsHeaders'); - } - this.state = HttpTransportState.ENDING; - return new network_1.ErrorResponse(statusCode, headers, info); - }; - HttpSubscription.prototype.verifyMessage = function (message) { - if (this.gotEOS) { - return new Error('Got another message after EOS message'); - } - if (!Array.isArray(message)) { - return new Error('Message is not an array'); - } - if (message.length < 1) { - return new Error('Message is empty array'); - } - }; - return HttpSubscription; -}()); -var HttpTransport = (function () { - function HttpTransport(host, encrypted) { - if (encrypted === void 0) { encrypted = true; } - this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; - } - HttpTransport.prototype.request = function (requestOptions) { - return this.createXHR(this.baseURL, requestOptions); - }; - HttpTransport.prototype.subscribe = function (path, listeners, headers) { - var requestOptions = { - headers: headers, - method: 'SUBSCRIBE', - path: path, - }; - return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); - }; - HttpTransport.prototype.createXHR = function (baseURL, options) { - var xhr = new self.XMLHttpRequest(); - var path = options.path.replace(/^\/+/, ''); - var endpoint = baseURL + "/" + path; - xhr.open(options.method.toUpperCase(), endpoint, true); - xhr = this.setJSONHeaderIfAppropriate(xhr, options); - if (options.jwt) { - xhr.setRequestHeader('authorization', "Bearer " + options.jwt); - } - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - return xhr; - }; - HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { - if (options.json) { - xhr.setRequestHeader('content-type', 'application/json'); - } - return xhr; - }; - return HttpTransport; -}()); -exports.default = HttpTransport; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var SubscribeMessageType = 100; -var OpenMessageType = 101; -var EventMessageType = 102; -var UnsubscribeMessageType = 198; -var EosMessageType = 199; -var PingMessageType = 16; -var PongMessageType = 17; -var CloseMessageType = 99; -var WSReadyState; -(function (WSReadyState) { - WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; - WSReadyState[WSReadyState["Open"] = 1] = "Open"; - WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; - WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; -})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); -var WsSubscriptions = (function () { - function WsSubscriptions() { - this.subscriptions = {}; - } - WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { - this.subscriptions[subID] = { - headers: headers, - listeners: listeners, - path: path, - }; - return subID; - }; - WsSubscriptions.prototype.has = function (subID) { - return this.subscriptions[subID] !== undefined; - }; - WsSubscriptions.prototype.isEmpty = function () { - return Object.keys(this.subscriptions).length === 0; - }; - WsSubscriptions.prototype.remove = function (subID) { - return delete this.subscriptions[subID]; - }; - WsSubscriptions.prototype.get = function (subID) { - return this.subscriptions[subID]; - }; - WsSubscriptions.prototype.getAll = function () { - return this.subscriptions; - }; - WsSubscriptions.prototype.getAllAsArray = function () { - var _this = this; - return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); - }; - WsSubscriptions.prototype.removeAll = function () { - this.subscriptions = {}; - }; - return WsSubscriptions; -}()); -var WsSubscription = (function () { - function WsSubscription(wsTransport, subID) { - this.wsTransport = wsTransport; - this.subID = subID; - } - WsSubscription.prototype.unsubscribe = function () { - this.wsTransport.unsubscribe(this.subID); - }; - return WsSubscription; -}()); -var pingIntervalMs = 30000; -var pingTimeoutMs = 10000; -var WebSocketTransport = (function () { - function WebSocketTransport(host) { - this.webSocketPath = '/ws'; - this.forcedClose = false; - this.closedError = null; - this.baseURL = "wss://" + host + this.webSocketPath; - this.lastSubscriptionID = 0; - this.subscriptions = new WsSubscriptions(); - this.pendingSubscriptions = new WsSubscriptions(); - this.connect(); - } - WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { - this.tryReconnectIfNeeded(); - var subID = this.lastSubscriptionID++; - if (this.socket.readyState !== WSReadyState.Open) { - this.pendingSubscriptions.add(subID, path, listeners, headers); - return new WsSubscription(this, subID); - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - return new WsSubscription(this, subID); - }; - WebSocketTransport.prototype.unsubscribe = function (subID) { - this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); - var subscription = this.subscriptions.get(subID); - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - this.subscriptions.remove(subID); - }; - WebSocketTransport.prototype.connect = function () { - var _this = this; - this.close(); - this.forcedClose = false; - this.closedError = null; - this.socket = new self.WebSocket(this.baseURL); - this.socket.onopen = function (event) { - var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); - allPendingSubscriptions.forEach(function (subscription) { - var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; - _this.subscribePending(path, listeners, headers, subID); - }); - _this.pendingSubscriptions.removeAll(); - _this.pingInterval = self.setInterval(function () { - if (_this.pongTimeout) { - return; - } - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - return; - } - _this.sendMessage(_this.getMessage(PingMessageType, now)); - _this.lastSentPingID = now; - _this.pongTimeout = self.setTimeout(function () { - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - _this.pongTimeout = null; - return; - } - _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); - }, pingTimeoutMs); - }, pingIntervalMs); - }; - this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; - this.socket.onerror = function (event) { - _this.close(new network_1.NetworkError('Connection was lost.')); - }; - this.socket.onclose = function (event) { - if (!_this.forcedClose) { - _this.tryReconnectIfNeeded(); - return; - } - var callback = _this.closedError - ? function (subscription) { - if (subscription.listeners.onError) { - subscription.listeners.onError(_this.closedError); - } - } - : function (subscription) { - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - }; - var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false - ? _this.pendingSubscriptions - : _this.subscriptions; - allSubscriptions.getAllAsArray().forEach(callback); - allSubscriptions.removeAll(); - if (_this.closedError) { - _this.tryReconnectIfNeeded(); - } - }; - }; - WebSocketTransport.prototype.close = function (error) { - if (!(this.socket instanceof self.WebSocket)) { - return; - } - this.forcedClose = true; - this.closedError = error; - this.socket.close(); - self.clearTimeout(this.pingInterval); - self.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.tryReconnectIfNeeded = function () { - if (this.socket.readyState !== WSReadyState.Closed) { - return; - } - this.connect(); - }; - WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { - if (subID === undefined) { - self.console.logger.debug("Subscription to path " + path + " has an undefined ID"); - return; - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - }; - WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { - return [messageType, id, path, headers]; - }; - WebSocketTransport.prototype.sendMessage = function (message) { - if (this.socket.readyState !== WSReadyState.Open) { - return self.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); - } - this.socket.send(JSON.stringify(message)); - }; - WebSocketTransport.prototype.subscription = function (subID) { - return this.subscriptions.get(subID); - }; - WebSocketTransport.prototype.receiveMessage = function (event) { - this.lastMessageReceivedTimestamp = new Date().getTime(); - var message; - try { - message = JSON.parse(event.data); - } - catch (err) { - this.close(new Error("Message is not valid JSON format. Getting " + event.data)); - return; - } - var nonValidMessageError = this.validateMessage(message); - if (nonValidMessageError) { - this.close(new Error(nonValidMessageError.message)); - return; - } - var messageType = message.shift(); - switch (messageType) { - case PongMessageType: - this.onPongMessage(message); - return; - case PingMessageType: - this.onPingMessage(message); - return; - case CloseMessageType: - this.onCloseMessage(message); - return; - } - var subID = message.shift(); - var subscription = this.subscription(subID); - if (!subscription) { - this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); - return; - } - var listeners = subscription.listeners; - switch (messageType) { - case OpenMessageType: - this.onOpenMessage(message, subID, listeners); - break; - case EventMessageType: - this.onEventMessage(message, listeners); - break; - case EosMessageType: - this.onEOSMessage(message, subID, listeners); - break; - default: - this.close(new Error('Received non existing type of message.')); - } - }; - WebSocketTransport.prototype.validateMessage = function (message) { - if (!Array.isArray(message)) { - return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); - } - if (message.length < 1) { - return new Error("Message is empty array: " + JSON.stringify(message)); - } - return null; - }; - WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { - if (subscriptionListeners.onOpen) { - subscriptionListeners.onOpen(message[1]); - } - }; - WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { - if (eventMessage.length !== 3) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; - if (typeof eventId !== 'string') { - return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); - } - if (subscriptionListeners.onEvent) { - subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); - } - }; - WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { - this.subscriptions.remove(subID); - if (eosMessage.length !== 3) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); - } - return; - } - var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; - if (typeof statusCode !== 'number') { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS Status Code')); - } - return; - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); - } - return; - } - if (statusCode === 204) { - if (subscriptionListeners.onEnd) { - subscriptionListeners.onEnd(null); - } - return; - } - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); - } - return; - }; - WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { - var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; - if (typeof statusCode !== 'number') { - return this.close(new Error('Close message: Invalid EOS Status Code')); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); - } - this.close(); - }; - WebSocketTransport.prototype.onPongMessage = function (message) { - var receviedPongID = message[0]; - if (this.lastSentPingID !== receviedPongID) { - this.close(new network_1.NetworkError("Didn't received pong with proper ID")); - } - self.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.onPingMessage = function (message) { - var receviedPingID = message[0]; - this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); - }; - return WebSocketTransport; -}()); -exports.default = WebSocketTransport; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -var host_base_1 = __webpack_require__(9); -var logger_1 = __webpack_require__(1); -var Instance = (function () { - function Instance(options) { - if (!options.locator) { - throw new Error('Expected `locator` property in Instance options!'); - } - var splitInstanceLocator = options.locator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instance locator property is in the wrong format!'); - } - if (!options.serviceName) { - throw new Error('Expected `serviceName` property in Instance options!'); - } - if (!options.serviceVersion) { - throw new Error('Expected `serviceVersion` property in Instance otpions!'); - } - this.platformVersion = splitInstanceLocator[0]; - this.cluster = splitInstanceLocator[1]; - this.id = splitInstanceLocator[2]; - this.serviceName = options.serviceName; - this.serviceVersion = options.serviceVersion; - this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.client = - options.client || - new base_client_1.BaseClient({ - encrypted: options.encrypted, - host: this.host, - logger: this.logger, - }); - this.tokenProvider = options.tokenProvider; - } - Instance.prototype.request = function (options, tokenParams) { - options.path = this.absPath(options.path); - if (options.headers == null || options.headers === undefined) { - options.headers = {}; - } - options.tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.request(options, tokenParams); - }; - Instance.prototype.subscribeNonResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); - }; - Instance.prototype.subscribeResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); - }; - Instance.prototype.absPath = function (relativePath) { - return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) - .replace(/\/+/g, '/') - .replace(/\/+$/, ''); - }; - return Instance; -}()); -exports.default = Instance; - - -/***/ }) -/******/ ]); - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var global_user_store_1 = __webpack_require__(10); -var payload_deserializer_1 = __webpack_require__(0); -var token_provider_1 = __webpack_require__(6); -var user_subscription_1 = __webpack_require__(21); -var ChatManager = (function () { - function ChatManager(options) { - if (typeof options.userId !== 'string') { - throw new Error('Please provide a userId to the ChatManger constructor!'); - } - this.userId = options.userId; - var splitInstanceLocator = options.instanceLocator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instanceLocator property is in the wrong format!'); - } - var cluster = splitInstanceLocator[1]; - var baseClient = options.baseClient || - new pusher_platform_1.BaseClient({ - host: cluster + "." + pusher_platform_1.HOST_BASE, - logger: options.logger, - }); - if (options.tokenProvider instanceof token_provider_1.default) { - options.tokenProvider.userId = this.userId; - } - var sharedInstanceOptions = { - client: baseClient, - locator: options.instanceLocator, - logger: options.logger, - tokenProvider: options.tokenProvider, - }; - this.apiInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.filesInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_files', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.cursorsInstance = new pusher_platform_1.Instance(__assign({ serviceName: 'chatkit_cursors', serviceVersion: 'v1' }, sharedInstanceOptions)); - this.userStore = new global_user_store_1.default({ apiInstance: this.apiInstance }); - } - ChatManager.prototype.connect = function (options) { - var _this = this; - var cursorsReq = this.cursorsInstance - .request({ - method: 'GET', - path: "/cursors/0/users/" + this.userId, - }) - .then(function (res) { - var cursors = JSON.parse(res); - var cursorsByRoom = {}; - cursors.forEach(function (c) { - cursorsByRoom[c.room_id] = payload_deserializer_1.default.createBasicCursorFromPayload(c); - }); - return cursorsByRoom; - }) - .catch(function (err) { - _this.cursorsInstance.logger.verbose('Error getting cursors:', err); - return {}; - }); - this.userSubscription = new user_subscription_1.default({ - apiInstance: this.apiInstance, - connectCompletionHandler: function (currentUser, error) { - if (currentUser) { - currentUser.cursorsReq = cursorsReq - .then(function (cursors) { - currentUser.cursors = cursors; - }); - options.onSuccess(currentUser); - } - else { - options.onError(error); - } - }, - cursorsInstance: this.cursorsInstance, - delegate: options.delegate, - filesInstance: this.filesInstance, - userStore: this.userStore, - }); - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: options.onError, - onEvent: this.userSubscription.handleEvent.bind(this.userSubscription), - }, - path: '/users', - }); - }; - return ChatManager; -}()); -exports.default = ChatManager; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var user_store_core_1 = __webpack_require__(5); -var utils_1 = __webpack_require__(1); -var GlobalUserStore = (function () { - function GlobalUserStore(options) { - this.apiInstance = options.apiInstance; - this.userStoreCore = options.userStoreCore || new user_store_core_1.default(); - } - GlobalUserStore.prototype.addOrMerge = function (user) { - return this.userStoreCore.addOrMerge(user); - }; - GlobalUserStore.prototype.remove = function (id) { - return this.userStoreCore.remove(id); - }; - GlobalUserStore.prototype.user = function (id, onSuccess, onError) { - this.findOrGetUser(id, onSuccess, onError); - }; - GlobalUserStore.prototype.findOrGetUser = function (id, onSuccess, onError) { - var user = this.userStoreCore.find(id); - if (user) { - onSuccess(user); - return; - } - this.getUser(id, onSuccess, onError); - }; - GlobalUserStore.prototype.getUser = function (id, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: "/users/" + id, - }) - .then(function (res) { - var userPayload = JSON.parse(res); - var user = payload_deserializer_1.default.createUserFromPayload(userPayload); - var userToReturn = _this.addOrMerge(user); - onSuccess(userToReturn); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - onError(error); - }); - }; - GlobalUserStore.prototype.handleInitialPresencePayloadsAfterRoomJoin = function (payloads, onComplete) { - this.handleInitialPresencePayloads(payloads, onComplete); - }; - GlobalUserStore.prototype.handleInitialPresencePayloads = function (payloads, onComplete) { - var _this = this; - var presencePayloadPromises = new Array(); - payloads.forEach(function (payload) { - var presencePromise = new Promise(function (resolve, reject) { - _this.user(payload.userId, function (user) { - user.updatePresenceInfoIfAppropriate(payload); - resolve(); - }, function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - reject(); - }); - }); - presencePayloadPromises.push(presencePromise); - }); - utils_1.allPromisesSettled(presencePayloadPromises).then(function () { - onComplete(); - }); - }; - GlobalUserStore.prototype.fetchUsersWithIds = function (userIds, onSuccess, onError) { - var _this = this; - if (userIds.length === 0) { - this.apiInstance.logger.verbose('Requested to fetch users for a list of user ids which was empty'); - onSuccess([]); - return; - } - var userIdsString = userIds.join(','); - var qs = utils_1.queryString({ user_ids: userIdsString }); - this.apiInstance - .request({ - method: 'GET', - path: "/users_by_ids" + qs, - }) - .then(function (res) { - var usersPayload = JSON.parse(res); - var users = usersPayload.map(function (userPayload) { - var user = payload_deserializer_1.default.createUserFromPayload(userPayload); - var addedOrUpdatedUser = _this.userStoreCore.addOrMerge(user); - return addedOrUpdatedUser; - }); - onSuccess(users); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error fetching user information:', error); - onError(error); - }); - }; - GlobalUserStore.prototype.initialFetchOfUsersWithIds = function (userIds, onSuccess, onError) { - this.fetchUsersWithIds(userIds, onSuccess, onError); - }; - return GlobalUserStore; -}()); -exports.default = GlobalUserStore; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) - t[p[i]] = s[p[i]]; - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var pusher_platform_1 = __webpack_require__(2); -var basic_message_enricher_1 = __webpack_require__(12); -var cursor_subscription_1 = __webpack_require__(13); -var cursor_types_1 = __webpack_require__(14); -var payload_deserializer_1 = __webpack_require__(0); -var presence_subscription_1 = __webpack_require__(15); -var room_store_1 = __webpack_require__(16); -var room_subscription_1 = __webpack_require__(17); -var constants_1 = __webpack_require__(3); -var utils_1 = __webpack_require__(1); -var CurrentUser = (function () { - function CurrentUser(options) { - var rooms = options.rooms, id = options.id, apiInstance = options.apiInstance, filesInstance = options.filesInstance, cursorsInstance = options.cursorsInstance; - var validRooms = rooms || []; - this.id = id; - this.createdAt = options.createdAt; - this.cursors = {}; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.roomStore = new room_store_1.default({ apiInstance: apiInstance, rooms: validRooms }); - this.apiInstance = apiInstance; - this.filesInstance = filesInstance; - this.cursorsInstance = cursorsInstance; - this.userStore = options.userStore; - this.pathFriendlyId = encodeURIComponent(id); - this.typingRequestSent = {}; - } - Object.defineProperty(CurrentUser.prototype, "rooms", { - get: function () { - return this.roomStore.rooms; - }, - enumerable: true, - configurable: true - }); - CurrentUser.prototype.updateWithPropertiesOf = function (currentUser) { - this.updatedAt = currentUser.updatedAt; - this.name = currentUser.name; - this.customData = currentUser.customData; - }; - CurrentUser.prototype.setupPresenceSubscription = function (delegate) { - this.presenceSubscription = new presence_subscription_1.default({ - apiInstance: this.apiInstance, - delegate: delegate, - roomStore: this.roomStore, - userStore: this.userStore, - }); - this.apiInstance.subscribeNonResuming({ - listeners: { - onError: delegate && delegate.error, - onEvent: this.presenceSubscription.handleEvent.bind(this.presenceSubscription), - }, - path: "/users/" + this.id + "/presence", - }); - }; - CurrentUser.prototype.createRoom = function (options, onSuccess, onError) { - var _this = this; - var roomData = { - created_by_id: this.id, - name: options.name, - private: options.private || false, - }; - if (options.addUserIds && options.addUserIds.length > 0) { - roomData['user_ids'] = options.addUserIds; - } - this.apiInstance - .request({ - json: roomData, - method: 'POST', - path: '/rooms', - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var addedOrMergedRoom = _this.roomStore.addOrMerge(room); - _this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error creating room:', error); - onError(error); - }); - }; - CurrentUser.prototype.populateRoomUserStore = function (room) { - var _this = this; - var userPromises = new Array(); - room.userIds.forEach(function (userId) { - var userPromise = new Promise(function (resolve, reject) { - _this.userStore.user(userId, function (user) { - room.userStore.addOrMerge(user); - resolve(); - }, function (error) { - _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room (room.name): " + error); - reject(); - }); - }); - userPromises.push(userPromise); - }); - utils_1.allPromisesSettled(userPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }; - CurrentUser.prototype.addUser = function (id, roomId, onSuccess, onError) { - this.addOrRemoveUsers(roomId, [id], 'add', onSuccess, onError); - }; - CurrentUser.prototype.removeUser = function (id, roomId, onSuccess, onError) { - this.addOrRemoveUsers(roomId, [id], 'remove', onSuccess, onError); - }; - CurrentUser.prototype.updateRoom = function (roomId, options, onSuccess, onError) { - var _this = this; - if (options.name === undefined && options.isPrivate === undefined) { - onSuccess(); - return; - } - var roomPayload = {}; - if (options.name) { - roomPayload['name'] = options.name; - } - if (options.isPrivate) { - roomPayload['private'] = options.isPrivate; - } - this.apiInstance - .request({ - json: roomPayload, - method: 'PUT', - path: "/rooms/" + roomId, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error updating room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.deleteRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'DELETE', - path: "/rooms/" + roomId, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error deleting room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.addOrRemoveUsers = function (roomId, userIds, membershipChange, onSuccess, onError) { - var _this = this; - var usersPayload = { - user_ids: userIds, - }; - this.apiInstance - .request({ - json: usersPayload, - method: 'PUT', - path: "/rooms/" + roomId + "/users/" + membershipChange, - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error when attempting to " + membershipChange + " users from room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.joinRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'POST', - path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/join", - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var addedOrMergedRoom = _this.roomStore.addOrMerge(room); - _this.populateRoomUserStore(addedOrMergedRoom); - onSuccess(addedOrMergedRoom); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error joining room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.leaveRoom = function (roomId, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'POST', - path: "/users/" + this.pathFriendlyId + "/rooms/" + roomId + "/leave", - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error leaving room " + roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.getJoinedRooms = function (onSuccess, onError) { - this.getUserRooms(false, onSuccess, onError); - }; - CurrentUser.prototype.getJoinableRooms = function (onSuccess, onError) { - this.getUserRooms(true, onSuccess, onError); - }; - CurrentUser.prototype.getUserRooms = function (onlyJoinable, onSuccess, onError) { - var joinableQueryItemValue = onlyJoinable ? 'true' : 'false'; - this.getRooms("/users/" + this.pathFriendlyId + "/rooms?joinable=" + joinableQueryItemValue, onSuccess, onError); - }; - CurrentUser.prototype.getAllRooms = function (onSuccess, onError) { - this.getRooms('/rooms', onSuccess, onError); - }; - CurrentUser.prototype.isTypingIn = function (roomId, onSuccess, onError) { - var _this = this; - var now = Date.now(); - var sent = this.typingRequestSent[roomId]; - var eventName = 'typing_start'; - var eventPayload = { - name: 'typing_start', - user_id: this.id, - }; - if (!sent || now - sent > constants_1.TYPING_REQ_TTL - constants_1.TYPING_REQ_LEEWAY) { - this.typingRequestSent[roomId] = now; - this.apiInstance - .request({ - json: eventPayload, - method: 'POST', - path: "/rooms/" + roomId + "/events", - }) - .then(function (res) { - onSuccess(); - }) - .catch(function (error) { - delete _this.typingRequestSent[roomId]; - _this.apiInstance.logger.verbose("Error sending " + eventName + " event in room " + roomId + ":", error); - onError(error); - }); - } - else { - onSuccess(); - } - }; - CurrentUser.prototype.setCursor = function (position, room, onSuccess, onError) { - var _this = this; - if (typeof position !== 'number') { - throw new Error('Cursor position should be a valid number'); - } - this.cursorsInstance - .request({ - json: { position: position }, - method: 'PUT', - path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id + "/users/" + this.id, - }) - .then(onSuccess) - .catch(function (err) { - _this.cursorsInstance.logger.verbose("Error setting cursor in room " + room.name + ":", err); - onError(err); - }); - }; - CurrentUser.prototype.sendMessage = function (options, onSuccess, onError) { - var _this = this; - var attachment = options.attachment, rest = __rest(options, ["attachment"]); - var completeOptions = __assign({ user_id: this.id }, rest); - if (attachment !== undefined) { - if (this.isDataAttachment(attachment)) { - var file = attachment.file, name = attachment.name; - this.uploadFile(file, name, options.roomId) - .then(function (fileRes) { - _this.sendMessageWithCompleteOptions(__assign({ attachment: fileRes, user_id: _this.id }, rest), onSuccess, onError); - }) - .catch(function (error) { - onError(error); - return; - }); - } - else if (this.isLinkAttachment(attachment)) { - var link = attachment.link, type = attachment.type; - completeOptions.attachment = { - resource_link: link, - type: type, - }; - this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); - } - else { - this.apiInstance.logger.debug('Message not sent: invalid attachment property provided: ', attachment); - } - } - else { - this.sendMessageWithCompleteOptions(completeOptions, onSuccess, onError); - } - }; - CurrentUser.prototype.subscribeToRoom = function (room, roomDelegate, messageLimit) { - var _this = this; - var path = "/rooms/" + room.id; - if (messageLimit !== undefined) { - if (typeof messageLimit !== 'number') { - throw new Error('Message limit should be a valid number'); - } - path = path + "?message_limit=" + messageLimit; - } - this.cursorsReq.then(function () { - room.subscription = new room_subscription_1.default({ - basicMessageEnricher: new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger), - delegate: roomDelegate, - logger: _this.apiInstance.logger, - }); - _this.apiInstance.subscribeNonResuming({ - listeners: { - onError: roomDelegate.error, - onEvent: room.subscription.handleEvent.bind(room.subscription), - }, - path: path, - }); - _this.subscribeToCursors(room, roomDelegate); - }); - }; - CurrentUser.prototype.fetchMessagesFromRoom = function (room, fetchOptions, onSuccess, onError) { - var _this = this; - var initialIdQueryParam = fetchOptions.initialId - ? "initial_id=" + fetchOptions.initialId - : ''; - var limitQueryParam = fetchOptions.limit - ? "limit=" + fetchOptions.limit - : ''; - var directionQueryParam = fetchOptions.direction - ? "direction=" + fetchOptions.direction - : 'direction=older'; - var combinedQueryParams = [ - initialIdQueryParam, - limitQueryParam, - directionQueryParam, - ].join('&'); - this.apiInstance - .request({ - method: 'GET', - path: "/rooms/" + room.id + "/messages?" + combinedQueryParams, - }) - .then(function (res) { - var messagesPayload = JSON.parse(res); - var messages = new Array(); - var basicMessages = new Array(); - var messageUserIds = messagesPayload.map(function (messagePayload) { - var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(messagePayload); - basicMessages.push(basicMessage); - return basicMessage.id; - }); - var messageUserIdsSet = new Set(messageUserIds); - var userIdsToFetch = Array.from(messageUserIdsSet.values()); - _this.userStore.fetchUsersWithIds(userIdsToFetch, function (users) { - var messageEnricher = new basic_message_enricher_1.default(_this.userStore, room, _this.apiInstance.logger); - var enrichmentPromises = new Array(); - basicMessages.forEach(function (basicMessage) { - var enrichmentPromise = new Promise(function (resolve, reject) { - messageEnricher.enrich(basicMessage, function (message) { - messages.push(message); - resolve(); - }, function (error) { - _this.apiInstance.logger.verbose("Unable to enrich basic mesage " + basicMessage.id + ": " + error); - reject(); - }); - }); - enrichmentPromises.push(enrichmentPromise); - }); - utils_1.allPromisesSettled(enrichmentPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - onSuccess(messages.sort(function (msgOne, msgTwo) { return msgOne.id - msgTwo.id; })); - }); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching users with ids " + userIdsToFetch + ":", error); - }); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error fetching messages froom room " + room.name + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.fetchAttachment = function (attachmentURL) { - if (!this.apiInstance.tokenProvider) { - return new Promise(function (resolve, reject) { - reject(new Error('Token provider not set on apiInstance')); - }); - } - return this.apiInstance.tokenProvider.fetchToken().then(function (token) { - return pusher_platform_1.sendRawRequest({ - headers: { - Authorization: "Bearer " + token, - }, - method: 'GET', - url: attachmentURL, - }).then(function (res) { - var attachmentPayload = JSON.parse(res); - var fetchedAttachment = payload_deserializer_1.default.createFetchedAttachmentFromPayload(attachmentPayload); - return fetchedAttachment; - }); - }); - }; - CurrentUser.prototype.isDataAttachment = function (attachment) { - return (attachment.file !== undefined && - attachment.name !== undefined); - }; - CurrentUser.prototype.isLinkAttachment = function (attachment) { - return (attachment.link !== undefined && - attachment.type !== undefined); - }; - CurrentUser.prototype.uploadFile = function (file, fileName, roomId) { - var data = new FormData(); - data.append('file', file, fileName); - return this.filesInstance - .request({ - body: data, - method: 'POST', - path: "/rooms/" + roomId + "/files/" + fileName, - }) - .then(function (res) { - return JSON.parse(res); - }); - }; - CurrentUser.prototype.sendMessageWithCompleteOptions = function (options, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - json: options, - method: 'POST', - path: "/rooms/" + options.roomId + "/messages", - }) - .then(function (res) { - var messageIdPayload = JSON.parse(res); - var messageId = messageIdPayload.message_id; - onSuccess(messageId); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose("Error sending message to room " + options.roomId + ":", error); - onError(error); - }); - }; - CurrentUser.prototype.subscribeToCursors = function (room, roomDelegate) { - var _this = this; - room.cursorSubscription = new cursor_subscription_1.default({ - delegate: roomDelegate, - handleCursorSetInternal: function (cursor) { - if (cursor.userId === _this.id && _this.cursors !== undefined) { - _this.cursors[cursor.roomId] = cursor; - } - }, - logger: this.cursorsInstance.logger, - room: room, - userStore: this.userStore, - }); - this.cursorsInstance.subscribeNonResuming({ - listeners: { - onEvent: room.cursorSubscription.handleEvent.bind(room.cursorSubscription), - }, - path: "/cursors/" + cursor_types_1.default.Read + "/rooms/" + room.id, - }); - }; - CurrentUser.prototype.getRooms = function (path, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: path, - }) - .then(function (res) { - var roomsPayload = JSON.parse(res); - var rooms = roomsPayload.map(function (roomPayload) { - return payload_deserializer_1.default.createRoomFromPayload(roomPayload); - }); - onSuccess(rooms); - }) - .catch(function (error) { - _this.apiInstance.logger.verbose('Error when getting instance rooms:', error); - onError(error); - }); - }; - return CurrentUser; -}()); -exports.default = CurrentUser; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var BasicMessageEnricher = (function () { - function BasicMessageEnricher(userStore, room, logger) { - this.completionOrderList = []; - this.messageIdToCompletionHandlers = {}; - this.enrichedMessagesAwaitingCompletionCalls = {}; - this.userIdsBeingRetrieved = []; - this.userIdsToBasicMessageIds = {}; - this.messagesAwaitingEnrichmentDependentOnUserRetrieval = {}; - this.userStore = userStore; - this.room = room; - this.logger = logger; - } - BasicMessageEnricher.prototype.enrich = function (basicMessage, onSuccess, onError) { - var _this = this; - var basicMessageId = basicMessage.id; - var basicMessageSenderId = basicMessage.senderId; - this.completionOrderList.push(basicMessageId); - this.messageIdToCompletionHandlers[basicMessageId] = { - onError: onError, - onSuccess: onSuccess, - }; - if (this.userIdsToBasicMessageIds[basicMessageSenderId] === undefined) { - this.userIdsToBasicMessageIds[basicMessageSenderId] = [basicMessageId]; - } - else { - this.userIdsToBasicMessageIds[basicMessageSenderId].push(basicMessageId); - } - this.messagesAwaitingEnrichmentDependentOnUserRetrieval[basicMessageId] = basicMessage; - if (this.userIdsBeingRetrieved.indexOf(basicMessageSenderId) > -1) { - return; - } - else { - this.userIdsBeingRetrieved.push(basicMessageSenderId); - } - this.userStore.user(basicMessageSenderId, function (user) { - var basicMessageIds = _this.userIdsToBasicMessageIds[basicMessageSenderId]; - if (basicMessageIds === undefined) { - _this.logger.verbose("Fetched user information for user with id " + user.id + " but no messages needed information for this user"); - return; - } - var basicMessages = basicMessageIds - .map(function (bmId) { - return _this.messagesAwaitingEnrichmentDependentOnUserRetrieval[bmId]; - }) - .filter(function (el) { return el !== undefined; }); - _this.enrichMessagesWithUser(user, basicMessages); - var indexToRemove = _this.userIdsBeingRetrieved.indexOf(basicMessageSenderId); - if (indexToRemove > -1) { - _this.userIdsBeingRetrieved.splice(indexToRemove, 1); - } - }, function (error) { - _this.logger.debug("Unable to find user with id " + basicMessage.senderId + ", associated with message " + basicMessageId + ". Error:", error); - _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessageId, error); - }); - }; - BasicMessageEnricher.prototype.enrichMessagesWithUser = function (user, messages) { - var _this = this; - messages.forEach(function (basicMessage) { - var message = { - attachment: basicMessage.attachment, - createdAt: basicMessage.createdAt, - id: basicMessage.id, - room: _this.room, - sender: user, - text: basicMessage.text, - updatedAt: basicMessage.updatedAt, - }; - _this.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(basicMessage.id, message); - }); - }; - BasicMessageEnricher.prototype.callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo = function (id, result) { - var nextIdToComplete = this.completionOrderList[0]; - if (nextIdToComplete === undefined) { - return; - } - this.enrichedMessagesAwaitingCompletionCalls[id] = result; - if (id !== nextIdToComplete) { - this.logger.verbose("Waiting to call completion handler for message id " + id + " as there are other older messages still to be enriched"); - return; - } - do { - var messageId = this.completionOrderList[0]; - var completionHandler = this.messageIdToCompletionHandlers[messageId]; - if (completionHandler === undefined) { - this.logger.verbose("Completion handler not stored for message id " + messageId); - return; - } - var res = this.enrichedMessagesAwaitingCompletionCalls[messageId]; - if (res === undefined) { - this.logger.verbose("Enrichment result not stored for message id " + messageId); - return; - } - if (res.sender !== undefined) { - completionHandler.onSuccess(res); - } - else { - completionHandler.onError(res); - } - this.completionOrderList.shift(); - delete this.messageIdToCompletionHandlers[messageId]; - delete this.enrichedMessagesAwaitingCompletionCalls[messageId]; - } while (this.completionOrderList[0] !== undefined && - this.enrichedMessagesAwaitingCompletionCalls[this.completionOrderList[0]] !== undefined); - }; - return BasicMessageEnricher; -}()); -exports.default = BasicMessageEnricher; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var CursorSubscription = (function () { - function CursorSubscription(options) { - this.delegate = options.delegate; - this.logger = options.logger; - this.room = options.room; - this.userStore = options.userStore; - this.handleCursorSetInternal = options.handleCursorSetInternal; - } - CursorSubscription.prototype.handleEvent = function (event) { - var _this = this; - if (!this.delegate || !this.delegate.cursorSet) { - return; - } - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - if (eventName !== 'cursor_set') { - this.logger.verbose("Cursor subscription received event with type " + eventName + ", when 'cursor_set' was expected"); - return; - } - this.logger.verbose("Received event name: " + eventName + ", and data: " + data); - var basicCursor = payload_deserializer_1.default.createBasicCursorFromPayload(data); - this.logger.verbose("Room received cursor for: " + basicCursor.userId); - this.handleCursorSetInternal(basicCursor); - this.enrich(basicCursor, function (cursor) { - if (_this.delegate && _this.delegate.cursorSet) { - _this.delegate.cursorSet(cursor); - } - }, function (error) { - _this.logger.debug('Error receiving cursor:', error); - }); - }; - CursorSubscription.prototype.enrich = function (basicCursor, onSuccess, onError) { - var _this = this; - this.userStore.user(basicCursor.userId, function (user) { - onSuccess({ - cursorType: basicCursor.cursorType, - position: basicCursor.position, - room: _this.room, - updatedAt: basicCursor.updatedAt, - user: user, - }); - }, function (error) { - _this.logger.debug("Unable to find user with id " + basicCursor.userId + ". Error:", error); - onError(error); - }); - }; - return CursorSubscription; -}()); -exports.default = CursorSubscription; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var CursorType; -(function (CursorType) { - CursorType[CursorType["Read"] = 0] = "Read"; -})(CursorType || (CursorType = {})); -exports.default = CursorType; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var PresenceSubscription = (function () { - function PresenceSubscription(options) { - this.apiInstance = options.apiInstance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.delegate = options.delegate; - } - PresenceSubscription.prototype.handleEvent = function (event) { - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - this.apiInstance.logger.verbose("Received event type: " + eventName + ", and data: " + data); - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'presence_update': - this.parsePresenceUpdatePayload(eventName, data, this.userStore); - break; - case 'join_room_presence_update': - this.parseJoinRoomPresenceUpdatePayload(eventName, data, this.userStore); - break; - default: - this.apiInstance.logger.verbose("Unsupported event type received: " + eventName + ", and data: " + data); - break; - } - }; - PresenceSubscription.prototype.end = function () { - }; - PresenceSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { - var _this = this; - var userStatesPayload = data.user_states; - if (userStatesPayload === undefined || - userStatesPayload.constructor !== Array) { - this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); - return; - } - var userStates = userStatesPayload - .map(function (userStatePayload) { - return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); - }) - .filter(function (el) { return el !== undefined; }); - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - this.userStore.handleInitialPresencePayloads(userStates, function () { - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }); - }; - PresenceSubscription.prototype.parsePresenceUpdatePayload = function (eventName, data, userStore) { - var _this = this; - var presencePayload = payload_deserializer_1.default.createPresencePayloadFromPayload(data); - userStore.user(presencePayload.userId, function (user) { - user.updatePresenceInfoIfAppropriate(presencePayload); - switch (presencePayload.state.stringValue) { - case 'online': - if (_this.delegate && _this.delegate.userCameOnline) { - _this.delegate.userCameOnline(user); - } - _this.apiInstance.logger.verbose(user.id + " came online"); - break; - case 'offline': - if (_this.delegate && _this.delegate.userWentOffline) { - _this.delegate.userWentOffline(user); - } - _this.apiInstance.logger.verbose(user.id + " went offline"); - break; - case 'unknown': - _this.apiInstance.logger.verbose("Somehow the presence state of user " + user.id + " is unknown"); - break; - } - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - return; - } - if (room.userIds.indexOf(user.id) > -1) { - switch (presencePayload.state.stringValue) { - case 'online': - if (room.subscription.delegate && - room.subscription.delegate.userCameOnlineInRoom) { - room.subscription.delegate.userCameOnlineInRoom(user); - } - break; - case 'offline': - if (room.subscription.delegate && - room.subscription.delegate.userWentOfflineInRoom) { - room.subscription.delegate.userWentOfflineInRoom(user); - } - break; - default: - break; - } - } - }); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching user information for user with id " + presencePayload.userId + ":", error); - return; - }); - }; - PresenceSubscription.prototype.parseJoinRoomPresenceUpdatePayload = function (eventName, data, userStore) { - var _this = this; - var userStatesPayload = data.user_states; - if (userStatesPayload === undefined || - userStatesPayload.constructor !== Array) { - this.apiInstance.logger.debug("'user_stats' value missing from " + eventName + " presence payload: " + data); - return; - } - var userStates = userStatesPayload - .map(function (userStatePayload) { - return payload_deserializer_1.default.createPresencePayloadFromPayload(userStatePayload); - }) - .filter(function (el) { return el !== undefined; }); - if (userStates.length === 0) { - this.apiInstance.logger.verbose('No presence user states to process'); - return; - } - this.userStore.handleInitialPresencePayloads(userStates, function () { - _this.roomStore.rooms.forEach(function (room) { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }); - }; - return PresenceSubscription; -}()); -exports.default = PresenceSubscription; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var RoomStore = (function () { - function RoomStore(options) { - this.rooms = options.rooms; - this.apiInstance = options.apiInstance; - } - RoomStore.prototype.room = function (id, onSuccess, onError) { - this.findOrGetRoom(id, onSuccess, onError); - }; - RoomStore.prototype.addOrMerge = function (room) { - var existingRoom = this.rooms.find(function (el) { return el.id === room.id; }); - if (existingRoom) { - existingRoom.updateWithPropertiesOfRoom(room); - return existingRoom; - } - else { - this.rooms.push(room); - return room; - } - }; - RoomStore.prototype.remove = function (id) { - var indexOfRoom = this.rooms.findIndex(function (el) { return el.id === id; }); - if (indexOfRoom === -1) { - return undefined; - } - var room = this.rooms[indexOfRoom]; - this.rooms.splice(indexOfRoom, 1); - return room; - }; - RoomStore.prototype.findOrGetRoom = function (id, onSuccess, onError) { - var room = this.rooms.find(function (el) { return el.id === id; }); - if (room) { - onSuccess(room); - } - else { - this.getRoom(id, onSuccess, onError); - } - }; - RoomStore.prototype.getRoom = function (id, onSuccess, onError) { - var _this = this; - this.apiInstance - .request({ - method: 'GET', - path: "/rooms/" + id, - }) - .then(function (res) { - var roomPayload = JSON.parse(res); - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - onSuccess(room); - }) - .catch(function (error) { - _this.apiInstance.logger.debug("Error fetching room " + id + ":", error); - onError(error); - }); - }; - return RoomStore; -}()); -exports.default = RoomStore; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var RoomSubscription = (function () { - function RoomSubscription(options) { - this.delegate = options.delegate; - this.basicMessageEnricher = options.basicMessageEnricher; - this.logger = options.logger; - } - RoomSubscription.prototype.handleEvent = function (event) { - var _this = this; - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - if (eventName !== 'new_message') { - this.logger.verbose("Room subscription received event with type " + eventName + ", when 'new_message' was expected"); - return; - } - this.logger.verbose("Received event name: " + eventName + ", and data:", data); - var basicMessage = payload_deserializer_1.default.createBasicMessageFromPayload(data); - this.basicMessageEnricher.enrich(basicMessage, function (message) { - _this.logger.verbose("Room received new message: " + message.text); - if (_this.delegate && _this.delegate.newMessage) { - _this.delegate.newMessage(message); - } - }, function (error) { - _this.logger.debug('Error receiving new message:', error); - }); - }; - return RoomSubscription; -}()); -exports.default = RoomSubscription; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var room_user_store_1 = __webpack_require__(19); -var Room = (function () { - function Room(options) { - this.id = options.id; - this.name = options.name; - this.isPrivate = options.isPrivate; - this.createdByUserId = options.createdByUserId; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.deletedAt = options.deletedAt; - this.userIds = options.userIds || []; - this.userStore = new room_user_store_1.default(); - } - Room.prototype.updateWithPropertiesOfRoom = function (room) { - this.name = room.name; - this.isPrivate = room.isPrivate; - this.updatedAt = room.updatedAt; - this.deletedAt = room.deletedAt; - this.userIds = room.userIds; - }; - return Room; -}()); -exports.default = Room; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var user_store_core_1 = __webpack_require__(5); -var RoomUserStore = (function () { - function RoomUserStore(userStoreCore) { - if (userStoreCore === void 0) { userStoreCore = new user_store_core_1.default(); } - this.userStoreCore = userStoreCore; - } - RoomUserStore.prototype.addOrMerge = function (user) { - return this.userStoreCore.addOrMerge(user); - }; - RoomUserStore.prototype.remove = function (id) { - return this.userStoreCore.remove(id); - }; - return RoomUserStore; -}()); -exports.default = RoomUserStore; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var presence_state_1 = __webpack_require__(4); -var User = (function () { - function User(options) { - this.id = options.id; - this.createdAt = options.createdAt; - this.updatedAt = options.updatedAt; - this.name = options.name; - this.avatarURL = options.avatarURL; - this.customData = options.customData; - this.presenceState = new presence_state_1.default('unknown'); - } - User.prototype.updateWithPropertiesOfUser = function (user) { - if (user.presenceState.stringValue !== 'unknown') { - this.presenceState = user.presenceState; - this.lastSeenAt = user.lastSeenAt; - } - return this; - }; - User.prototype.updatePresenceInfoIfAppropriate = function (newInfoPayload) { - if (newInfoPayload.state.stringValue !== 'unknown') { - this.presenceState = newInfoPayload.state; - this.lastSeenAt = newInfoPayload.lastSeenAt; - } - }; - return User; -}()); -exports.default = User; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var payload_deserializer_1 = __webpack_require__(0); -var constants_1 = __webpack_require__(3); -var utils_1 = __webpack_require__(1); -var UserSubscription = (function () { - function UserSubscription(options) { - this.typingTimers = {}; - this.apiInstance = options.apiInstance; - this.filesInstance = options.filesInstance; - this.cursorsInstance = options.cursorsInstance; - this.userStore = options.userStore; - this.delegate = options.delegate; - this.connectCompletionHandlers = [options.connectCompletionHandler]; - } - UserSubscription.prototype.handleEvent = function (event) { - var body = event.body, eventId = event.eventId, headers = event.headers; - var data = body.data; - var eventName = body.event_name; - this.apiInstance.logger.verbose("Received event name: " + eventName + ", and data: " + data); - switch (eventName) { - case 'initial_state': - this.parseInitialStatePayload(eventName, data, this.userStore); - break; - case 'added_to_room': - this.parseAddedToRoomPayload(eventName, data); - break; - case 'removed_from_room': - this.parseRemovedFromRoomPayload(eventName, data); - break; - case 'room_updated': - this.parseRoomUpdatedPayload(eventName, data); - break; - case 'room_deleted': - this.parseRoomDeletedPayload(eventName, data); - break; - case 'user_joined': - this.parseUserJoinedPayload(eventName, data); - break; - case 'user_left': - this.parseUserLeftPayload(eventName, data); - break; - case 'typing_start': - this.parseIsTypingPayload(eventName, data, data.user_id); - break; - case 'typing_stop': - break; - } - }; - UserSubscription.prototype.callConnectCompletionHandlers = function (currentUser, error) { - this.connectCompletionHandlers.forEach(function (completionHandler) { - completionHandler(currentUser, error); - }); - }; - UserSubscription.prototype.parseInitialStatePayload = function (eventName, data, userStore) { - var _this = this; - var roomsPayload = data.rooms; - var userPayload = data.current_user; - var receivedCurrentUser = payload_deserializer_1.default.createCurrentUserFromPayload(userPayload, this.apiInstance, this.filesInstance, this.cursorsInstance, this.userStore); - var wasExistingCurrentUser = this.currentUser !== undefined; - if (this.currentUser) { - this.currentUser.updateWithPropertiesOf(receivedCurrentUser); - } - else { - this.currentUser = receivedCurrentUser; - } - var receivedRoomsConstructor = roomsPayload.constructor; - if (receivedRoomsConstructor !== Array) { - throw TypeError('`rooms` key of initial_state payload was of type `${receivedRoomsConstructor}`, expected `Array`'); - } - if (roomsPayload.length === 0) { - this.currentUser.setupPresenceSubscription(this.delegate); - this.callConnectCompletionHandlers(this.currentUser); - return; - } - var combinedRoomUserIds = new Set([]); - var roomsFromConnection = []; - roomsPayload.forEach(function (roomPayload) { - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - room.userIds.forEach(function (userId) { - combinedRoomUserIds.add(userId); - }); - roomsFromConnection.push(room); - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.roomStore.addOrMerge(room); - }); - this.callConnectCompletionHandlers(this.currentUser); - this.fetchInitialUserInformationForUserIds(combinedRoomUserIds, this.currentUser); - if (wasExistingCurrentUser) { - this.reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection); - } - }; - UserSubscription.prototype.fetchInitialUserInformationForUserIds = function (userIds, currentUser) { - var _this = this; - var userIdsArray = Array.from(userIds.values()); - this.userStore.initialFetchOfUsersWithIds(userIdsArray, function (users) { - var combinedRoomUsersPromises = new Array(); - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.roomStore.rooms.forEach(function (room) { - var roomPromise = new Promise(function (roomResolve, roomReject) { - var roomUsersPromises = new Array(); - room.userIds.forEach(function (userId) { - var userPromise = new Promise(function (userResolve, userReject) { - _this.userStore.user(userId, function (user) { - room.userStore.addOrMerge(user); - userResolve(); - }, function (error) { - _this.apiInstance.logger.verbose("Unable to fetch information about user " + userId); - userReject(); - }); - }); - roomUsersPromises.push(userPromise); - }); - utils_1.allPromisesSettled(roomUsersPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name + "\""); - roomResolve(); - }); - }); - combinedRoomUsersPromises.push(roomPromise); - }); - utils_1.allPromisesSettled(combinedRoomUsersPromises).then(function () { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.setupPresenceSubscription(_this.delegate); - }); - }, function (error) { - _this.apiInstance.logger.debug("Unable to fetch user information after successful connection: " + error); - return; - }); - }; - UserSubscription.prototype.reconcileExistingRoomStoreWithRoomsReceivedOnConnection = function (roomsFromConnection) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property of UserSubscription unset after successful connection'); - return; - } - var roomStoreRooms = this.currentUser.roomStore.rooms; - var mostRecentConnectionRoomsSet = new Set(roomsFromConnection); - var noLongerAMemberOfRooms = roomStoreRooms.filter(function (room) { return !mostRecentConnectionRoomsSet.has(room); }); - noLongerAMemberOfRooms.forEach(function (room) { - if (_this.delegate && _this.delegate.removedFromRoom) { - _this.delegate.removedFromRoom(room); - } - }); - }; - UserSubscription.prototype.parseAddedToRoomPayload = function (eventName, data) { - var _this = this; - var roomPayload = data.room; - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose("`room` key missing or invalid in `added_to_room` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - var roomAdded = this.currentUser.roomStore.addOrMerge(room); - if (this.delegate && this.delegate.addedToRoom) { - this.delegate.addedToRoom(room); - } - this.apiInstance.logger.verbose("Added to room: " + room.name); - var roomUsersPromises = new Array(); - roomAdded.userIds.forEach(function (userId) { - var userPromise = new Promise(function (resolve, reject) { - _this.userStore.user(userId, function (user) { - _this.apiInstance.logger.verbose("Added user id " + userId + " to room " + room.name); - room.userStore.addOrMerge(user); - resolve(); - }, function (error) { - _this.apiInstance.logger.debug("Unable to add user with id " + userId + " to room " + room.name + ": " + error); - reject(); - }); - }); - roomUsersPromises.push(userPromise); - }); - utils_1.allPromisesSettled(roomUsersPromises).then(function () { - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.usersUpdated) { - room.subscription.delegate.usersUpdated(); - } - } - _this.apiInstance.logger.verbose("Users updated in room " + room.name); - }); - }; - UserSubscription.prototype.parseRemovedFromRoomPayload = function (eventName, data) { - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `removed_from_room` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var roomRemoved = this.currentUser.roomStore.remove(roomId); - if (roomRemoved) { - if (this.delegate && this.delegate.removedFromRoom) { - this.delegate.removedFromRoom(roomRemoved); - } - this.apiInstance.logger.verbose("Removed from room: " + roomRemoved.name); - } - else { - this.apiInstance.logger.verbose("Received `removed_from_room` API event but room with ID " + roomId + " not found in local store of joined rooms"); - return; - } - }; - UserSubscription.prototype.parseRoomUpdatedPayload = function (eventName, data) { - var _this = this; - var roomPayload = data.room; - if (roomPayload === undefined || typeof roomPayload !== 'object') { - this.apiInstance.logger.verbose("`room` key missing or invalid in `room_updated` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var room = payload_deserializer_1.default.createRoomFromPayload(roomPayload); - this.currentUser.roomStore.room(room.id, function (roomToUpdate) { - roomToUpdate.updateWithPropertiesOfRoom(room); - if (_this.delegate && _this.delegate.roomUpdated) { - _this.delegate.roomUpdated(roomToUpdate); - } - _this.apiInstance.logger.verbose("Room updated: " + room.name); - }, function (error) { - _this.apiInstance.logger.debug("Error updating room " + room.id + ":", error); - }); - }; - UserSubscription.prototype.parseRoomDeletedPayload = function (eventName, data) { - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `room_deleted` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - var deletedRoom = this.currentUser.roomStore.remove(roomId); - if (deletedRoom) { - if (this.delegate && this.delegate.roomDeleted) { - this.delegate.roomDeleted(deletedRoom); - } - this.apiInstance.logger.verbose("Room deleted: " + deletedRoom.name); - } - else { - this.apiInstance.logger.verbose("Received `room_deleted` API event but room with ID " + roomId + " not found in local store of joined rooms"); - return; - } - }; - UserSubscription.prototype.parseUserJoinedPayload = function (eventName, data) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_joined` payload: " + data); - return; - } - var userId = data.user_id; - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_joined` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - var addedOrMergedUser = room.userStore.addOrMerge(user); - if (room.userIds.indexOf(addedOrMergedUser.id) === -1) { - room.userIds.push(addedOrMergedUser.id); - } - if (_this.delegate && _this.delegate.userJoinedRoom) { - _this.delegate.userJoinedRoom(room, addedOrMergedUser); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userJoined) { - room.subscription.delegate.userJoined(addedOrMergedUser); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " joined room: " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); - return; - }); - }; - UserSubscription.prototype.parseUserLeftPayload = function (eventName, data) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `user_left` payload: " + data); - return; - } - var userId = data.user_id; - if (userId === undefined || typeof userId !== 'string') { - this.apiInstance.logger.verbose("`user_id` key missing or invalid in `user_left` payload: " + data); - return; - } - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - var roomUserIdIndex = room.userIds.indexOf(user.id); - if (roomUserIdIndex > -1) { - room.userIds.splice(roomUserIdIndex, 1); - } - room.userStore.remove(user.id); - if (_this.delegate && _this.delegate.userLeftRoom) { - _this.delegate.userLeftRoom(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userLeft) { - room.subscription.delegate.userLeft(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " left room " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " left room with id " + roomId + " but no information about the user could be retrieved. Error was: " + error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("User with id " + userId + " joined room with id " + roomId + " but no information about the room could be retrieved. Error was: " + error); - return; - }); - }; - UserSubscription.prototype.parseIsTypingPayload = function (eventName, data, userId) { - var _this = this; - var roomId = data.room_id; - if (roomId === undefined || typeof roomId !== 'number') { - this.apiInstance.logger.verbose("`room_id` key missing or invalid in `typing_start` payload: " + data); - return; - } - if (!this.typingTimers[roomId]) { - this.typingTimers[roomId] = {}; - } - if (this.typingTimers[roomId][userId]) { - clearTimeout(this.typingTimers[roomId][userId]); - } - else { - this.startedTyping(roomId, userId); - } - this.typingTimers[roomId][userId] = setTimeout(function () { - _this.stoppedTyping(roomId, userId); - delete _this.typingTimers[roomId][userId]; - }, constants_1.TYPING_REQ_TTL); - }; - UserSubscription.prototype.startedTyping = function (roomId, userId) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - if (_this.delegate && _this.delegate.userStartedTyping) { - _this.delegate.userStartedTyping(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userStartedTyping) { - room.subscription.delegate.userStartedTyping(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " started typing in room " + room.name); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching information for user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.verbose("Error fetching information for room " + roomId + ":", error); - return; - }); - }; - UserSubscription.prototype.stoppedTyping = function (roomId, userId) { - var _this = this; - if (!this.currentUser) { - this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - this.currentUser.roomStore.room(roomId, function (room) { - if (!_this.currentUser) { - _this.apiInstance.logger.verbose('currentUser property not set on UserSubscription'); - return; - } - _this.currentUser.userStore.user(userId, function (user) { - if (_this.delegate && _this.delegate.userStoppedTyping) { - _this.delegate.userStoppedTyping(room, user); - } - if (room.subscription === undefined) { - _this.apiInstance.logger.verbose("Room " + room.name + " has no subscription object set"); - } - else { - if (room.subscription.delegate && - room.subscription.delegate.userStoppedTyping) { - room.subscription.delegate.userStoppedTyping(user); - } - } - _this.apiInstance.logger.verbose("User " + user.id + " stopped typing in room " + room.name); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching information for user " + userId + ":", error); - return; - }); - }, function (error) { - _this.apiInstance.logger.debug("Error fetching information for room " + roomId + ":", error); - return; - }); - }; - return UserSubscription; -}()); -exports.default = UserSubscription; - - -/***/ }) -/******/ ]); \ No newline at end of file diff --git a/dist/worker/declarations/attachment.d.ts b/dist/worker/declarations/attachment.d.ts deleted file mode 100644 index 1e89409..0000000 --- a/dist/worker/declarations/attachment.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface Attachment { - fetchRequired: boolean; - link: string; - type: string; -} -export default Attachment; diff --git a/dist/worker/declarations/basic_cursor.d.ts b/dist/worker/declarations/basic_cursor.d.ts deleted file mode 100644 index 1ab80b5..0000000 --- a/dist/worker/declarations/basic_cursor.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface BasicCursor { - cursorType: number; - position: number; - roomId: number; - updatedAt: string; - userId: string; -} -export default BasicCursor; diff --git a/dist/worker/declarations/basic_message.d.ts b/dist/worker/declarations/basic_message.d.ts deleted file mode 100644 index b28e155..0000000 --- a/dist/worker/declarations/basic_message.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Attachment from './attachment'; -interface BasicMessage { - id: number; - senderId: string; - roomId: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; -} -export default BasicMessage; diff --git a/dist/worker/declarations/basic_message_enricher.d.ts b/dist/worker/declarations/basic_message_enricher.d.ts deleted file mode 100644 index a8f7e15..0000000 --- a/dist/worker/declarations/basic_message_enricher.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Logger } from 'pusher-platform'; -import BasicMessage from './basic_message'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import Room from './room'; -import User from './user'; -export interface MessageEnrichmentCompletionHandlers { - onSuccess: (message: Message) => void; - onError: (error: any) => void; -} -export declare type MessageIdsToCompletionHandlers = { - [key: number]: MessageEnrichmentCompletionHandlers; -}; -export declare type UserIdsToBasicMessageIds = { - [key: string]: number[]; -}; -export declare type MessageEnrichmentResult = Message | any; -export declare type MessageIdsToEnrichmentResults = { - [key: number]: MessageEnrichmentResult; -}; -export declare type MessageIdsToBasicMessages = { - [key: number]: BasicMessage; -}; -export default class BasicMessageEnricher { - userStore: GlobalUserStore; - room: Room; - logger: Logger; - private completionOrderList; - private messageIdToCompletionHandlers; - private enrichedMessagesAwaitingCompletionCalls; - private userIdsBeingRetrieved; - private userIdsToBasicMessageIds; - private messagesAwaitingEnrichmentDependentOnUserRetrieval; - constructor(userStore: GlobalUserStore, room: Room, logger: Logger); - enrich(basicMessage: BasicMessage, onSuccess: (message: Message) => void, onError: (error: any) => void): void; - enrichMessagesWithUser(user: User, messages: BasicMessage[]): void; - callCompletionHandlersForEnrichedMessagesWithIdsLessThanOrEqualTo(id: number, result: MessageEnrichmentResult): void; -} diff --git a/dist/worker/declarations/basic_user.d.ts b/dist/worker/declarations/basic_user.d.ts deleted file mode 100644 index fb90490..0000000 --- a/dist/worker/declarations/basic_user.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface BasicUser { - id: string; - createdAt: string; - updatedAt: string; -} -export default BasicUser; diff --git a/dist/worker/declarations/chat_manager.d.ts b/dist/worker/declarations/chat_manager.d.ts deleted file mode 100644 index 49a8817..0000000 --- a/dist/worker/declarations/chat_manager.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BaseClient, Instance, Logger, TokenProvider } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -export interface ChatManagerOptions { - instanceLocator: string; - tokenProvider: TokenProvider; - logger?: Logger; - baseClient?: BaseClient; - userId: string; -} -export default class ChatManager { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userId: string; - private userStore; - private userSubscription; - constructor(options: ChatManagerOptions); - connect(options: ConnectOptions): void; -} -export interface ConnectOptions { - delegate?: ChatManagerDelegate; - onSuccess: (currentUser: CurrentUser) => void; - onError: (error: any) => void; -} diff --git a/dist/worker/declarations/chat_manager_delegate.d.ts b/dist/worker/declarations/chat_manager_delegate.d.ts deleted file mode 100644 index 5b2d790..0000000 --- a/dist/worker/declarations/chat_manager_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Room from './room'; -import User from './user'; -interface ChatManagerDelegate { - addedToRoom?: (room: Room) => void; - removedFromRoom?: (room: Room) => void; - roomUpdated?: (room: Room) => void; - roomDeleted?: (room: Room) => void; - userStartedTyping?: (room: Room, user: User) => void; - userStoppedTyping?: (room: Room, user: User) => void; - userJoinedRoom?: (room: Room, user: User) => void; - userLeftRoom?: (room: Room, user: User) => void; - userCameOnline?: (user: User) => void; - userWentOffline?: (user: User) => void; - error?: (error: any) => void; -} -export default ChatManagerDelegate; diff --git a/dist/worker/declarations/constants.d.ts b/dist/worker/declarations/constants.d.ts deleted file mode 100644 index d18fd38..0000000 --- a/dist/worker/declarations/constants.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare const TYPING_REQ_TTL = 1500; -export declare const TYPING_REQ_LEEWAY = 500; diff --git a/dist/worker/declarations/current_user.d.ts b/dist/worker/declarations/current_user.d.ts deleted file mode 100644 index 77a8eae..0000000 --- a/dist/worker/declarations/current_user.d.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Instance } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import Message from './message'; -import PresenceSubscription from './presence_subscription'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -import RoomStore from './room_store'; -export interface CreateRoomOptions { - name: string; - private?: boolean; - addUserIds?: string[]; -} -export interface UpdateRoomOptions { - name?: string; - isPrivate?: boolean; -} -export interface FetchRoomMessagesOptions { - initialId?: string; - limit?: number; - direction?: string; -} -export interface CurrentUserOptions { - id: string; - createdAt: string; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - rooms?: Room[]; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; -} -export interface DataAttachment { - file: Blob; - name: string; -} -export interface LinkAttachment { - link: string; - type: string; -} -export declare type GenericAttachment = LinkAttachment | DataAttachment; -export interface AttachmentBody { - resource_link: string; - type: string; -} -export interface SendMessageOptions { - attachment?: GenericAttachment; - roomId: number; - text?: string; -} -export interface CompleteMessageOptions { - attachment?: AttachmentBody; - roomId: number; - text?: string; - user_id: string; -} -export default class CurrentUser { - id: string; - createdAt: string; - cursors: { - [roomId: string]: BasicCursor; - }; - cursorsReq: Promise; - updatedAt: string; - name?: string; - avatarURL?: string; - customData?: any; - userStore: GlobalUserStore; - roomStore: RoomStore; - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - pathFriendlyId: string; - presenceSubscription: PresenceSubscription; - typingRequestSent: { - [roomId: string]: number; - }; - readonly rooms: Room[]; - constructor(options: CurrentUserOptions); - updateWithPropertiesOf(currentUser: CurrentUser): void; - setupPresenceSubscription(delegate?: ChatManagerDelegate): void; - createRoom(options: CreateRoomOptions, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - populateRoomUserStore(room: Room): void; - addUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - removeUser(id: string, roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - updateRoom(roomId: number, options: UpdateRoomOptions, onSuccess: () => void, onError: (error: any) => void): void; - deleteRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - addOrRemoveUsers(roomId: number, userIds: string[], membershipChange: string, onSuccess: () => void, onError: (error: any) => void): void; - joinRoom(roomId: number, onSuccess: (room: Room) => void, onError: (error: any) => void): void; - leaveRoom(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - getJoinedRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getJoinableRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getUserRooms(onlyJoinable: boolean, onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - getAllRooms(onSuccess: (rooms: Room[]) => void, onError: (error: any) => void): void; - isTypingIn(roomId: number, onSuccess: () => void, onError: (error: any) => void): void; - setCursor(position: number, room: Room, onSuccess: () => void, onError: (error: any) => void): void; - sendMessage(options: SendMessageOptions, onSuccess: (messageId: number) => void, onError: (error: any) => void): void; - subscribeToRoom(room: Room, roomDelegate: RoomDelegate, messageLimit?: number): void; - fetchMessagesFromRoom(room: Room, fetchOptions: FetchRoomMessagesOptions, onSuccess: (messages: Message[]) => void, onError: (error: any) => void): void; - fetchAttachment(attachmentURL: string): Promise; - private isDataAttachment(attachment); - private isLinkAttachment(attachment); - private uploadFile(file, fileName, roomId); - private sendMessageWithCompleteOptions(options, onSuccess, onError); - private subscribeToCursors(room, roomDelegate); - private getRooms(path, onSuccess, onError); -} diff --git a/dist/worker/declarations/cursor.d.ts b/dist/worker/declarations/cursor.d.ts deleted file mode 100644 index 3aa3524..0000000 --- a/dist/worker/declarations/cursor.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Room from './room'; -import User from './user'; -interface Cursor { - cursorType: number; - position: number; - room: Room; - updatedAt: string; - user: User; -} -export default Cursor; diff --git a/dist/worker/declarations/cursor_subscription.d.ts b/dist/worker/declarations/cursor_subscription.d.ts deleted file mode 100644 index 08e991b..0000000 --- a/dist/worker/declarations/cursor_subscription.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicCursor from './basic_cursor'; -import Cursor from './cursor'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -import RoomDelegate from './room_delegate'; -export interface CursorSubscriptionOptions { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; -} -export default class CursorSubscription { - delegate?: RoomDelegate; - logger: Logger; - room: Room; - userStore: GlobalUserStore; - handleCursorSetInternal: (cursor: BasicCursor) => void; - constructor(options: CursorSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - enrich(basicCursor: BasicCursor, onSuccess: (cursor: Cursor) => void, onError: (error: any) => void): void; -} diff --git a/dist/worker/declarations/cursor_types.d.ts b/dist/worker/declarations/cursor_types.d.ts deleted file mode 100644 index 01f22f7..0000000 --- a/dist/worker/declarations/cursor_types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare enum CursorType { - Read = 0, -} -export default CursorType; diff --git a/dist/worker/declarations/fetched_attachment.d.ts b/dist/worker/declarations/fetched_attachment.d.ts deleted file mode 100644 index 907eddc..0000000 --- a/dist/worker/declarations/fetched_attachment.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface FetchedAttachmentFile { - bytes: number; - lastModified: number; - name: string; -} -interface FetchedAttachment { - file: FetchedAttachmentFile; - link: string; - ttl: number; -} -export default FetchedAttachment; diff --git a/dist/worker/declarations/global_user_store.d.ts b/dist/worker/declarations/global_user_store.d.ts deleted file mode 100644 index 7712fe4..0000000 --- a/dist/worker/declarations/global_user_store.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import PresencePayload from './presence_payload'; -import User from './user'; -import UserStoreCore from './user_store_core'; -export interface GlobalUserStoreOptions { - apiInstance: Instance; - userStoreCore?: UserStoreCore; -} -export default class GlobalUserStore { - private apiInstance; - private userStoreCore; - constructor(options: GlobalUserStoreOptions); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - user(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - findOrGetUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - getUser(id: string, onSuccess: (user: User) => void, onError: (error: any) => void): void; - handleInitialPresencePayloadsAfterRoomJoin(payloads: PresencePayload[], onComplete: () => void): void; - handleInitialPresencePayloads(payloads: PresencePayload[], onComplete: () => void): void; - fetchUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; - initialFetchOfUsersWithIds(userIds: string[], onSuccess: (users: User[]) => void, onError: (error: Error) => void): void; -} diff --git a/dist/worker/declarations/index.d.ts b/dist/worker/declarations/index.d.ts deleted file mode 100644 index 8118af7..0000000 --- a/dist/worker/declarations/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BaseClient } from 'pusher-platform'; -import ChatManager from './chat_manager'; -import TokenProvider from './token_provider'; -export { BaseClient, ChatManager, TokenProvider }; -declare const _default: { - BaseClient: typeof BaseClient; - ChatManager: typeof ChatManager; - TokenProvider: typeof TokenProvider; -}; -export default _default; diff --git a/dist/worker/declarations/message.d.ts b/dist/worker/declarations/message.d.ts deleted file mode 100644 index d7bd58d..0000000 --- a/dist/worker/declarations/message.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Attachment from './attachment'; -import Room from './room'; -import User from './user'; -interface Message { - id: number; - text: string; - createdAt: string; - updatedAt: string; - attachment?: Attachment; - sender: User; - room: Room; -} -export default Message; diff --git a/dist/worker/declarations/payload_deserializer.d.ts b/dist/worker/declarations/payload_deserializer.d.ts deleted file mode 100644 index bb635f2..0000000 --- a/dist/worker/declarations/payload_deserializer.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Attachment from './attachment'; -import BasicCursor from './basic_cursor'; -import BasicMessage from './basic_message'; -import BasicUser from './basic_user'; -import CurrentUser from './current_user'; -import FetchedAttachment from './fetched_attachment'; -import GlobalUserStore from './global_user_store'; -import PresencePayload from './presence_payload'; -import Room from './room'; -import User from './user'; -export default class PayloadDeserializer { - static createUserFromPayload(userPayload: any): User; - static createCurrentUserFromPayload(userPayload: any, apiInstance: Instance, filesInstance: Instance, cursorsInstance: Instance, userStore: GlobalUserStore): CurrentUser; - static createRoomFromPayload(roomPayload: any): Room; - static createBasicMessageFromPayload(messagePayload: any): BasicMessage; - static createBasicCursorFromPayload(payload: any): BasicCursor; - static createPresencePayloadFromPayload(payload: any): PresencePayload; - static createBasicUserFromPayload(payload: any): BasicUser; - static createAttachmentFromPayload(payload: any): Attachment | undefined; - static createFetchedAttachmentFromPayload(payload: any): FetchedAttachment | undefined; -} diff --git a/dist/worker/declarations/presence_payload.d.ts b/dist/worker/declarations/presence_payload.d.ts deleted file mode 100644 index c2a2215..0000000 --- a/dist/worker/declarations/presence_payload.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import PresenceState from './presence_state'; -interface PresencePayload { - userId: string; - state: PresenceState; - lastSeenAt?: string; -} -export default PresencePayload; diff --git a/dist/worker/declarations/presence_state.d.ts b/dist/worker/declarations/presence_state.d.ts deleted file mode 100644 index b7bd7d0..0000000 --- a/dist/worker/declarations/presence_state.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default class PresenceState { - stringValue: string; - constructor(state: string); -} diff --git a/dist/worker/declarations/presence_subscription.d.ts b/dist/worker/declarations/presence_subscription.d.ts deleted file mode 100644 index 53583cc..0000000 --- a/dist/worker/declarations/presence_subscription.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import GlobalUserStore from './global_user_store'; -import RoomStore from './room_store'; -export interface PresenceSubscriptionOptions { - apiInstance: Instance; - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; -} -export default class PresenceSubscription { - userStore: GlobalUserStore; - roomStore: RoomStore; - delegate?: ChatManagerDelegate; - private apiInstance; - constructor(options: PresenceSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - end(): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parsePresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - parseJoinRoomPresenceUpdatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; -} diff --git a/dist/worker/declarations/room.d.ts b/dist/worker/declarations/room.d.ts deleted file mode 100644 index f62e355..0000000 --- a/dist/worker/declarations/room.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import CursorSubscription from './cursor_subscription'; -import RoomSubscription from './room_subscription'; -import RoomUserStore from './room_user_store'; -export interface RoomOptions { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds?: string[]; -} -export default class Room { - id: number; - name: string; - isPrivate: boolean; - createdByUserId: string; - createdAt: string; - updatedAt: string; - deletedAt?: string; - userIds: string[]; - userStore: RoomUserStore; - subscription?: RoomSubscription; - cursorSubscription?: CursorSubscription; - constructor(options: RoomOptions); - updateWithPropertiesOfRoom(room: Room): void; -} diff --git a/dist/worker/declarations/room_delegate.d.ts b/dist/worker/declarations/room_delegate.d.ts deleted file mode 100644 index fbfb142..0000000 --- a/dist/worker/declarations/room_delegate.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Cursor from './cursor'; -import Message from './message'; -import User from './user'; -interface RoomDelegate { - newMessage?: (message: Message) => void; - userStartedTyping?: (user: User) => void; - userStoppedTyping?: (user: User) => void; - userJoined?: (user: User) => void; - userLeft?: (user: User) => void; - userCameOnlineInRoom?: (user: User) => void; - userWentOfflineInRoom?: (user: User) => void; - usersUpdated?: () => void; - error?: (error: any) => void; - cursorSet?: (cursor: Cursor) => void; -} -export default RoomDelegate; diff --git a/dist/worker/declarations/room_store.d.ts b/dist/worker/declarations/room_store.d.ts deleted file mode 100644 index 9d9befa..0000000 --- a/dist/worker/declarations/room_store.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Instance } from 'pusher-platform'; -import Room from './room'; -export interface RoomStoreOptions { - rooms: Room[]; - apiInstance: Instance; -} -export default class RoomStore { - rooms: Room[]; - apiInstance: Instance; - constructor(options: RoomStoreOptions); - room(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - addOrMerge(room: Room): Room; - remove(id: number): Room | undefined; - findOrGetRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; - getRoom(id: number, onSuccess: (room: Room) => void, onError: (error: Error) => void): void; -} diff --git a/dist/worker/declarations/room_subscription.d.ts b/dist/worker/declarations/room_subscription.d.ts deleted file mode 100644 index c37121a..0000000 --- a/dist/worker/declarations/room_subscription.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Logger, SubscriptionEvent } from 'pusher-platform'; -import BasicMessageEnricher from './basic_message_enricher'; -import RoomDelegate from './room_delegate'; -export interface RoomSubscriptionOptions { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; -} -export default class RoomSubscription { - delegate?: RoomDelegate; - basicMessageEnricher: BasicMessageEnricher; - logger: Logger; - constructor(options: RoomSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; -} diff --git a/dist/worker/declarations/room_user_store.d.ts b/dist/worker/declarations/room_user_store.d.ts deleted file mode 100644 index eb1f60f..0000000 --- a/dist/worker/declarations/room_user_store.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -import UserStoreCore from './user_store_core'; -export default class RoomUserStore { - private userStoreCore; - constructor(userStoreCore?: UserStoreCore); - addOrMerge(user: User): User; - remove(id: string): User | undefined; -} diff --git a/dist/worker/declarations/token_provider.d.ts b/dist/worker/declarations/token_provider.d.ts deleted file mode 100644 index 5fb85e9..0000000 --- a/dist/worker/declarations/token_provider.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TokenProvider as PlatformTokenProvider } from 'pusher-platform'; -export interface TokenProviderAuthContextOptions { - queryParams?: TokenProviderAuthContextQueryParams; - headers?: TokenProviderAuthContextHeaders; -} -export declare type TokenProviderAuthContextHeaders = { - [key: string]: string; -}; -export declare type TokenProviderAuthContextQueryParams = { - [key: string]: string; -}; -export interface TokenProviderOptions { - authContext?: TokenProviderAuthContextOptions; - url: string; -} -export default class TokenProvider implements PlatformTokenProvider { - authContext?: TokenProviderAuthContextOptions; - url: string; - userId?: string; - cachedAccessToken?: string; - cachedTokenExpiresAt?: number; - constructor(options: TokenProviderOptions); - readonly cacheIsStale: boolean; - fetchToken(tokenParams?: any): Promise; - clearToken(token?: string): void; - makeAuthRequest(): Promise; - private cache(accessToken, expiresIn); - private unixTimeNow(); -} diff --git a/dist/worker/declarations/user.d.ts b/dist/worker/declarations/user.d.ts deleted file mode 100644 index 7e0b5f4..0000000 --- a/dist/worker/declarations/user.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import PresencePayload from './presence_payload'; -import PresenceState from './presence_state'; -export interface UserOptions { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; -} -export default class User { - id: string; - createdAt: string; - updatedAt: string; - name: string; - avatarURL: string; - customData: any; - presenceState: PresenceState; - lastSeenAt?: string; - constructor(options: UserOptions); - updateWithPropertiesOfUser(user: User): this; - updatePresenceInfoIfAppropriate(newInfoPayload: PresencePayload): void; -} diff --git a/dist/worker/declarations/user_store_core.d.ts b/dist/worker/declarations/user_store_core.d.ts deleted file mode 100644 index a55ef61..0000000 --- a/dist/worker/declarations/user_store_core.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import User from './user'; -export default class UserStoreCore { - private users; - constructor(users?: User[]); - addOrMerge(user: User): User; - remove(id: string): User | undefined; - find(id: string): User | undefined; -} diff --git a/dist/worker/declarations/user_subscription.d.ts b/dist/worker/declarations/user_subscription.d.ts deleted file mode 100644 index 42ea461..0000000 --- a/dist/worker/declarations/user_subscription.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Instance, SubscriptionEvent } from 'pusher-platform'; -import ChatManagerDelegate from './chat_manager_delegate'; -import CurrentUser from './current_user'; -import GlobalUserStore from './global_user_store'; -import Room from './room'; -export interface UserSubscriptionOptions { - apiInstance: Instance; - filesInstance: Instance; - cursorsInstance: Instance; - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandler: (currentUser?: CurrentUser, error?: any) => void; -} -export default class UserSubscription { - userStore: GlobalUserStore; - delegate?: ChatManagerDelegate; - connectCompletionHandlers: [(currentUser?: CurrentUser, error?: any) => void]; - currentUser?: CurrentUser; - private apiInstance; - private filesInstance; - private cursorsInstance; - private typingTimers; - constructor(options: UserSubscriptionOptions); - handleEvent(event: SubscriptionEvent): void; - callConnectCompletionHandlers(currentUser?: CurrentUser, error?: Error): void; - parseInitialStatePayload(eventName: string, data: any, userStore: GlobalUserStore): void; - fetchInitialUserInformationForUserIds(userIds: Set, currentUser: CurrentUser): void; - reconcileExistingRoomStoreWithRoomsReceivedOnConnection(roomsFromConnection: Room[]): void; - parseAddedToRoomPayload(eventName: string, data: any): void; - parseRemovedFromRoomPayload(eventName: string, data: any): void; - parseRoomUpdatedPayload(eventName: string, data: any): void; - parseRoomDeletedPayload(eventName: string, data: any): void; - parseUserJoinedPayload(eventName: string, data: any): void; - parseUserLeftPayload(eventName: string, data: any): void; - parseIsTypingPayload(eventName: string, data: any, userId: string): void; - private startedTyping(roomId, userId); - private stoppedTyping(roomId, userId); -} diff --git a/dist/worker/declarations/utils.d.ts b/dist/worker/declarations/utils.d.ts deleted file mode 100644 index dbf28ce..0000000 --- a/dist/worker/declarations/utils.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export declare function urlEncode(data: any): string; -export declare function queryString(data: any): string; -export declare function queryParamsFromFullUrl(url: string): any; -export declare function mergeQueryParamsIntoUrl(urlString: string, queryParams: any): string; -export declare function allPromisesSettled(promises: Array>): Promise; From 806dc1c8cf68e5dafcff29c2904dc42a2b751ffe Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 10:29:56 +0000 Subject: [PATCH 42/99] encode user ids in path --- dist/web/chatkit.js | 12 ++++++------ src/current-user.js | 8 ++++---- src/presence-subscription.js | 2 +- src/user-store.js | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js index 8125208..1aaa1b3 100644 --- a/dist/web/chatkit.js +++ b/dist/web/chatkit.js @@ -5752,7 +5752,7 @@ var UserStore = function UserStore(_ref) { this.fetchBasicUser = function (userId) { return _this.instance.request({ method: 'GET', - path: '/users/' + userId + path: '/users/' + encodeURIComponent(userId) }).then(function (res) { var user = parseUser(JSON.parse(res)); _this.set(userId, user); @@ -6238,7 +6238,7 @@ var PresenceSubscription = function () { return new Promise(function (resolve, reject) { _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); _this2.instance.subscribeNonResuming({ - path: '/users/' + _this2.userId + '/presence', + path: '/users/' + encodeURIComponent(_this2.userId) + '/presence', listeners: { onError: reject, onEvent: _this2.onEvent @@ -6390,10 +6390,9 @@ var CurrentUser = function () { }; this.getJoinableRooms = function () { - // TODO path friendly ids everywhere return _this.apiInstance.request({ method: 'GET', - path: '/users/' + _this.id + '/rooms?joinable=true' + path: '/users/' + encodeURIComponent(_this.id) + '/rooms?joinable=true' }).then(pipe(JSON.parse, map(parseBasicRoom))).catch(function (err) { _this.logger.warn('error getting joinable rooms:', err); throw err; @@ -6408,7 +6407,7 @@ var CurrentUser = function () { typeCheck('roomId', 'number', roomId); return _this.apiInstance.request({ method: 'POST', - path: '/users/' + _this.id + '/rooms/' + roomId + '/join' + path: '/users/' + encodeURIComponent(_this.id) + '/rooms/' + roomId + '/join' }).then(function (res) { var basicRoom = parseBasicRoom(JSON.parse(res)); return _this.roomStore.set(basicRoom.id, basicRoom); @@ -6422,7 +6421,7 @@ var CurrentUser = function () { typeCheck('roomId', 'number', roomId); return _this.apiInstance.request({ method: 'POST', - path: '/users/' + _this.id + '/rooms/' + roomId + '/leave' + path: '/users/' + encodeURIComponent(_this.id) + '/rooms/' + roomId + '/leave' }).then(function () { return _this.roomStore.pop(roomId); }).catch(function (err) { @@ -6516,6 +6515,7 @@ var CurrentUser = function () { var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var messageLimit = arguments[2]; + // TODO join room if not already a member typeCheck('roomId', 'number', roomId); typeCheckObj('hooks', 'function', hooks); messageLimit && typeCheck('messageLimit', 'number', messageLimit); diff --git a/src/current-user.js b/src/current-user.js index a863232..706746e 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -91,11 +91,10 @@ export class CurrentUser { } getJoinableRooms = () => { - // TODO path friendly ids everywhere return this.apiInstance .request({ method: 'GET', - path: `/users/${this.id}/rooms?joinable=true` + path: `/users/${encodeURIComponent(this.id)}/rooms?joinable=true` }) .then(pipe(JSON.parse, map(parseBasicRoom))) .catch(err => { @@ -113,7 +112,7 @@ export class CurrentUser { return this.apiInstance .request({ method: 'POST', - path: `/users/${this.id}/rooms/${roomId}/join` + path: `/users/${encodeURIComponent(this.id)}/rooms/${roomId}/join` }) .then(res => { const basicRoom = parseBasicRoom(JSON.parse(res)) @@ -130,7 +129,7 @@ export class CurrentUser { return this.apiInstance .request({ method: 'POST', - path: `/users/${this.id}/rooms/${roomId}/leave` + path: `/users/${encodeURIComponent(this.id)}/rooms/${roomId}/leave` }) .then(() => this.roomStore.pop(roomId)) .catch(err => { @@ -225,6 +224,7 @@ export class CurrentUser { } subscribeToRoom = (roomId, hooks = {}, messageLimit) => { + // TODO join room if not already a member typeCheck('roomId', 'number', roomId) typeCheckObj('hooks', 'function', hooks) messageLimit && typeCheck('messageLimit', 'number', messageLimit) diff --git a/src/presence-subscription.js b/src/presence-subscription.js index 970556a..550dfb9 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -26,7 +26,7 @@ export class PresenceSubscription { return new Promise((resolve, reject) => { this.hooks = { ...this.hooks, subscriptionEstablished: resolve } this.instance.subscribeNonResuming({ - path: `/users/${this.userId}/presence`, + path: `/users/${encodeURIComponent(this.userId)}/presence`, listeners: { onError: reject, onEvent: this.onEvent diff --git a/src/user-store.js b/src/user-store.js index f4ab57b..1b854ba 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -35,7 +35,7 @@ export class UserStore { return this.instance .request({ method: 'GET', - path: `/users/${userId}` + path: `/users/${encodeURIComponent(userId)}` }) .then(res => { const user = parseUser(JSON.parse(res)) From d159ae8222383e8222c38f24201578b424dd454f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 10:31:22 +0000 Subject: [PATCH 43/99] remove redundant todos --- src/typing-indicators.js | 2 +- src/user-subscription.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/typing-indicators.js b/src/typing-indicators.js index e05014c..52febfd 100644 --- a/src/typing-indicators.js +++ b/src/typing-indicators.js @@ -21,7 +21,7 @@ export class TypingIndicators { method: 'POST', path: `/rooms/${roomId}/events`, json: { - name: 'typing_start', // TODO 'is_typing' + name: 'typing_start', // soon to be 'is_typing' user_id: this.userId } }) diff --git a/src/user-subscription.js b/src/user-subscription.js index f3a1543..98d5a91 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -49,7 +49,7 @@ export class UserSubscription { case 'room_deleted': this.onRoomDeleted(body.data) break - case 'typing_start': // TODO 'is_typing' + case 'typing_start': // soon to be 'is_typing' this.onIsTyping(body.data) break } From 8676afc74fe16a9ed1504a8966def1b01e855fde Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 11:15:19 +0000 Subject: [PATCH 44/99] token cache --- dist/web/chatkit.js | 45 +++++++++++++++++++++++++++++++++++++------ src/token-provider.js | 36 +++++++++++++++++++++++++++------- src/utils.js | 2 ++ tests/main.js | 16 ++++++++------- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js index 1aaa1b3..14b3d64 100644 --- a/dist/web/chatkit.js +++ b/dist/web/chatkit.js @@ -5592,6 +5592,10 @@ var checkOneOf = function checkOneOf(name, values, value) { // pointfree debugging +var unixSeconds = function unixSeconds() { + return Math.floor(Date.now() / 1000); +}; + var TokenProvider = // TODO authContext function TokenProvider() { @@ -5603,19 +5607,48 @@ function TokenProvider() { classCallCheck(this, TokenProvider); this.fetchToken = function () { + return !_this.cacheIsStale() ? Promise.resolve(_this.cachedToken) : _this.fetchFreshToken().then(function (_ref2) { + var token = _ref2.token, + expiresIn = _ref2.expiresIn; + + _this.cache(token, expiresIn); + return token; + }); + }; + + this.fetchFreshToken = function () { return pusherPlatform_4({ + method: 'POST', + url: appendQueryParam('user_id', _this.userId, _this.url), body: urlEncode({ grant_type: 'client_credentials' }), headers: { 'content-type': 'application/x-www-form-urlencoded' - }, - method: 'POST', - url: appendQueryParam('user_id', _this.userId, _this.url) + } }).then(function (res) { - return JSON.parse(res).access_token; + var _JSON$parse = JSON.parse(res), + token = _JSON$parse.access_token, + expiresIn = _JSON$parse.expires_in; + + return { token: token, expiresIn: expiresIn }; }); }; + this.cacheIsStale = function () { + return !_this.cachedToken || unixSeconds() > _this.cacheExpiresAt; + }; + + this.cache = function (token, expiresIn) { + _this.cachedToken = token; + _this.cacheExpiresAt = unixSeconds() + expiresIn; + }; + + this.clearCache = function () { + _this.cachedToken = undefined; + _this.cacheExpiresAt = undefined; + }; + this.setUserId = function (userId) { + _this.clearCache(); _this.userId = userId; }; @@ -5924,7 +5957,7 @@ var TypingIndicators = function TypingIndicators(_ref) { method: 'POST', path: '/rooms/' + roomId + '/events', json: { - name: 'typing_start', // TODO 'is_typing' + name: 'typing_start', // soon to be 'is_typing' user_id: _this.userId } }).catch(function (err) { @@ -6006,7 +6039,7 @@ var UserSubscription = function () { _this.onRoomDeleted(body.data); break; case 'typing_start': - // TODO 'is_typing' + // soon to be 'is_typing' _this.onIsTyping(body.data); break; } diff --git a/src/token-provider.js b/src/token-provider.js index f3a790c..4129595 100644 --- a/src/token-provider.js +++ b/src/token-provider.js @@ -1,6 +1,6 @@ import { sendRawRequest } from 'pusher-platform' -import { urlEncode, appendQueryParam, typeCheck } from './utils' +import { appendQueryParam, typeCheck, unixSeconds, urlEncode } from './utils' export class TokenProvider { // TODO authContext @@ -9,19 +9,41 @@ export class TokenProvider { this.url = url } - // TODO caching - fetchToken = () => sendRawRequest({ + fetchToken = () => !this.cacheIsStale() + ? Promise.resolve(this.cachedToken) + : this.fetchFreshToken().then(({ token, expiresIn }) => { + this.cache(token, expiresIn) + return token + }) + + fetchFreshToken = () => sendRawRequest({ + method: 'POST', + url: appendQueryParam('user_id', this.userId, this.url), body: urlEncode({ grant_type: 'client_credentials' }), headers: { 'content-type': 'application/x-www-form-urlencoded' - }, - method: 'POST', - url: appendQueryParam('user_id', this.userId, this.url) - }).then(res => JSON.parse(res).access_token) + } + }).then(res => { + const { access_token: token, expires_in: expiresIn } = JSON.parse(res) + return { token, expiresIn } + }) + + cacheIsStale = () => !this.cachedToken || unixSeconds() > this.cacheExpiresAt + + cache = (token, expiresIn) => { + this.cachedToken = token + this.cacheExpiresAt = unixSeconds() + expiresIn + } + + clearCache = () => { + this.cachedToken = undefined + this.cacheExpiresAt = undefined + } // To allow ChatManager to feed the userId to the TokenProvider. Not set // directly so as not to mess with a custom TokenProvider implementation. setUserId = userId => { + this.clearCache() this.userId = userId } } diff --git a/src/utils.js b/src/utils.js index 430250c..e293443 100644 --- a/src/utils.js +++ b/src/utils.js @@ -54,6 +54,8 @@ export const checkOneOf = (name, values, value) => { } } +export const unixSeconds = () => Math.floor(Date.now() / 1000) + // pointfree debugging export const trace = msg => x => { console.log(msg, x) diff --git a/tests/main.js b/tests/main.js index c53754c..27170ad 100644 --- a/tests/main.js +++ b/tests/main.js @@ -56,10 +56,12 @@ const batch = (n, f) => { const concatBatch = (n, f) => batch(n, compose(f, reduce(concat, []))) +const tokenProvider = new TokenProvider({ url: TOKEN_PROVIDER_URL }) + const fetchUser = (t, userId, hooks = {}) => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId, - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }), + tokenProvider, logger: { error: console.log, warn: console.log, @@ -123,7 +125,7 @@ test('instantiate ChatManager with correct params', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }) t.equal(typeof chatManager, 'object') t.equal(typeof chatManager.connect, 'function') @@ -134,7 +136,7 @@ test('instantiate ChatManager with non-string instanceLocator fails', t => { t.throws(() => new ChatManager({ instanceLocator: 42, userId: 'alice', - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }), /instanceLocator/) t.end() }) @@ -143,7 +145,7 @@ test('instantiate ChatManager without userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }), /userId/) t.end() }) @@ -152,7 +154,7 @@ test('instantiate ChatManager with non-string userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }), /string/) t.end() }) @@ -170,7 +172,7 @@ test('connection fails if provided with non-function hooks', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }) t.throws( () => chatManager.connect({ nonFunction: 42 }), @@ -183,7 +185,7 @@ test('connection fails for nonexistent user', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) + tokenProvider }) chatManager.connect() .then(() => { From 9b3da3a542ae5f945a3a8d962b50621a01490899 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 11:33:42 +0000 Subject: [PATCH 45/99] comments --- src/chat-manager.js | 1 - src/user-store.js | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chat-manager.js b/src/chat-manager.js index b712b3e..c2fb949 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -5,7 +5,6 @@ import { CurrentUser } from './current-user' import { typeCheck, typeCheckObj } from './utils' export class ChatManager { - // TODO accept a tokenProviderUrl and create a default tokenProvider? constructor ({ instanceLocator, tokenProvider, userId, ...options } = {}) { typeCheck('instanceLocator', 'string', instanceLocator) typeCheck('tokenProvider', 'object', tokenProvider) diff --git a/src/user-store.js b/src/user-store.js index 1b854ba..731d4eb 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -56,7 +56,9 @@ export class UserStore { if (length(missing) === 0) { return Promise.resolve() } - // TODO don't make simulatneous requests for the same users + // TODO don't make simulatneous requests for the same users (question: what + // will actually cause this situation to arise? Receiving lots of messages + // in a room from a user who is no longer a member of said room?) return this.instance .request({ method: 'GET', From 79686369b5544adaf6508ca9a1ae0a739e682951 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 11:34:02 +0000 Subject: [PATCH 46/99] failing test --- tests/main.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/main.js b/tests/main.js index 27170ad..4384cae 100644 --- a/tests/main.js +++ b/tests/main.js @@ -19,7 +19,7 @@ import ChatkitServer from 'pusher-chatkit-server' import { TokenProvider, ChatManager } from '../dist/web/chatkit.js' import { INSTANCE_LOCATOR, INSTANCE_KEY, TOKEN_PROVIDER_URL } from './config' -let alicesRoom, bobsRoom, alicesPrivateRoom +let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom const TEST_TIMEOUT = 15 * 1000 @@ -647,11 +647,28 @@ test('subscribe to room and receive sent messages', t => { test('[setup] create Carol', t => { server.createUser('carol', 'Carol') - .then(() => t.end()) + .then(() => server.createRoom('carol', { name: `Carol's room` })) + .then(room => { + carolsRoom = room // we'll want this in the following tests + t.end() + }) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) +test('subscribe to room implicitly joins', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(carolsRoom.id) + .then(() => { + t.true( + any(r => r.id === carolsRoom.id, alice.rooms), + `Alice's rooms include Carol's room` + ) + }) + ) + t.timeoutAfter(TEST_TIMEOUT) +}) + test(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => alice.subscribeToRoom(bobsRoom.id, { From 21a031ef905e899dc8f00f30f39b5d6c7c179200 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 11:59:46 +0000 Subject: [PATCH 47/99] implicitly join room on subscribe if not already a member --- dist/web/chatkit.js | 26 ++++++++++++++++++-------- src/current-user.js | 14 ++++++++++++-- tests/main.js | 6 ++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js index 14b3d64..65ba995 100644 --- a/dist/web/chatkit.js +++ b/dist/web/chatkit.js @@ -5590,12 +5590,12 @@ var checkOneOf = function checkOneOf(name, values, value) { } }; -// pointfree debugging - var unixSeconds = function unixSeconds() { return Math.floor(Date.now() / 1000); }; +// pointfree debugging + var TokenProvider = // TODO authContext function TokenProvider() { @@ -5801,7 +5801,9 @@ var UserStore = function UserStore(_ref) { if (length(missing) === 0) { return Promise.resolve(); } - // TODO don't make simulatneous requests for the same users + // TODO don't make simulatneous requests for the same users (question: what + // will actually cause this situation to arise? Receiving lots of messages + // in a room from a user who is no longer a member of said room?) return _this.instance.request({ method: 'GET', path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') @@ -6438,6 +6440,9 @@ var CurrentUser = function () { this.joinRoom = function (roomId) { typeCheck('roomId', 'number', roomId); + if (_this.isMemberOf(roomId)) { + return _this.roomStore.get(roomId); + } return _this.apiInstance.request({ method: 'POST', path: '/users/' + encodeURIComponent(_this.id) + '/rooms/' + roomId + '/join' @@ -6548,7 +6553,6 @@ var CurrentUser = function () { var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var messageLimit = arguments[2]; - // TODO join room if not already a member typeCheck('roomId', 'number', roomId); typeCheckObj('hooks', 'function', hooks); messageLimit && typeCheck('messageLimit', 'number', messageLimit); @@ -6564,7 +6568,15 @@ var CurrentUser = function () { roomStore: _this.roomStore, logger: _this.logger }); - return _this.roomSubscriptions[roomId].connect(); + return _this.joinRoom(roomId).then(function () { + return _this.roomSubscriptions[roomId].connect(); + }).catch(function (err) { + return _this.logger.error('error subscribing to room ' + roomId, err); + }); + }; + + this.isMemberOf = function (roomId) { + return contains$1(roomId, map(prop('id'), _this.rooms)); }; this.decorateMessage = function (basicMessage) { @@ -6659,9 +6671,7 @@ var CurrentUser = function () { return CurrentUser; }(); -var ChatManager = -// TODO accept a tokenProviderUrl and create a default tokenProvider? -function ChatManager() { +var ChatManager = function ChatManager() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; diff --git a/src/current-user.js b/src/current-user.js index 706746e..04af935 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -2,6 +2,7 @@ import { chain, compose, concat, + contains, indexBy, map, pipe, @@ -109,6 +110,9 @@ export class CurrentUser { joinRoom = roomId => { typeCheck('roomId', 'number', roomId) + if (this.isMemberOf(roomId)) { + return this.roomStore.get(roomId) + } return this.apiInstance .request({ method: 'POST', @@ -224,7 +228,6 @@ export class CurrentUser { } subscribeToRoom = (roomId, hooks = {}, messageLimit) => { - // TODO join room if not already a member typeCheck('roomId', 'number', roomId) typeCheckObj('hooks', 'function', hooks) messageLimit && typeCheck('messageLimit', 'number', messageLimit) @@ -240,11 +243,18 @@ export class CurrentUser { roomStore: this.roomStore, logger: this.logger }) - return this.roomSubscriptions[roomId].connect() + return this.joinRoom(roomId) + .then(() => this.roomSubscriptions[roomId].connect()) + .catch(err => this.logger.error( + `error subscribing to room ${roomId}`, + err + )) } /* internal */ + isMemberOf = roomId => contains(roomId, map(prop('id'), this.rooms)) + decorateMessage = basicMessage => new Message( basicMessage, this.userStore, diff --git a/tests/main.js b/tests/main.js index 4384cae..f59c1c0 100644 --- a/tests/main.js +++ b/tests/main.js @@ -78,6 +78,9 @@ const sendMessages = (user, room, texts) => length(texts) === 0 : user.sendMessage({ roomId: room.id, text: head(texts) }) .then(() => sendMessages(user, room, tail(texts))) +// Teardown first so that we can kill the tests at any time, safe in the +// knowledge that we'll always be starting with a blank slate next time + test('[teardown] destroy Alice', t => { server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) t.timeoutAfter(TEST_TIMEOUT) @@ -664,8 +667,11 @@ test('subscribe to room implicitly joins', t => { any(r => r.id === carolsRoom.id, alice.rooms), `Alice's rooms include Carol's room` ) + t.end() }) + .catch(endWithErr(t)) ) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 1b5fcc0e1497678f3f52f11f0f86ad16a2ab51aa Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 13:49:07 +0000 Subject: [PATCH 48/99] tests --- tests/main.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/main.js b/tests/main.js index f59c1c0..d8bdd18 100644 --- a/tests/main.js +++ b/tests/main.js @@ -733,11 +733,7 @@ test('typing indicators', t => { })), fetchUser(t, 'carol') ]) - .then(([x, carol]) => carol.isTypingIn( - bobsRoom.id, - () => {}, - endWithErr(t) - )) + .then(([x, carol]) => carol.isTypingIn(bobsRoom.id)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From 33f03ce3a35471dcda4645ce3e3ba51010ec0b1f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 14:21:35 +0000 Subject: [PATCH 49/99] return room from subscribeToRoom --- dist/web/chatkit.js | 6 ++++-- src/current-user.js | 2 +- tests/main.js | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js index 65ba995..77f5747 100644 --- a/dist/web/chatkit.js +++ b/dist/web/chatkit.js @@ -6568,8 +6568,10 @@ var CurrentUser = function () { roomStore: _this.roomStore, logger: _this.logger }); - return _this.joinRoom(roomId).then(function () { - return _this.roomSubscriptions[roomId].connect(); + return _this.joinRoom(roomId).then(function (room) { + return _this.roomSubscriptions[roomId].connect().then(function () { + return room; + }); }).catch(function (err) { return _this.logger.error('error subscribing to room ' + roomId, err); }); diff --git a/src/current-user.js b/src/current-user.js index 04af935..f42a123 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -244,7 +244,7 @@ export class CurrentUser { logger: this.logger }) return this.joinRoom(roomId) - .then(() => this.roomSubscriptions[roomId].connect()) + .then(room => this.roomSubscriptions[roomId].connect().then(() => room)) .catch(err => this.logger.error( `error subscribing to room ${roomId}`, err diff --git a/tests/main.js b/tests/main.js index d8bdd18..b12c49f 100644 --- a/tests/main.js +++ b/tests/main.js @@ -662,7 +662,9 @@ test('[setup] create Carol', t => { test('subscribe to room implicitly joins', t => { fetchUser(t, 'alice') .then(alice => alice.subscribeToRoom(carolsRoom.id) - .then(() => { + .then(room => { + t.equal(room.id, carolsRoom.id) + t.true(room.name, `Carol's room`) t.true( any(r => r.id === carolsRoom.id, alice.rooms), `Alice's rooms include Carol's room` From da233fefacfec3356054c18a3e808d51b0884c88 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 14:50:22 +0000 Subject: [PATCH 50/99] remove dist --- dist/web/chatkit.js | 6742 ------------------------------------------- 1 file changed, 6742 deletions(-) delete mode 100644 dist/web/chatkit.js diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js deleted file mode 100644 index 77f5747..0000000 --- a/dist/web/chatkit.js +++ /dev/null @@ -1,6742 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Chatkit = factory()); -}(this, (function () { 'use strict'; - -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - - -function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -var pusherPlatform = createCommonjsModule(function (module, exports) { -(function webpackUniversalModuleDefinition(root, factory) { - module.exports = factory(); -})(commonjsGlobal, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -function responseToHeadersObject(headerStr) { - var headers = {}; - if (!headerStr) { - return headers; - } - var headerPairs = headerStr.split('\u000d\u000a'); - for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { - var headerPair = headerPairs_1[_i]; - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - return headers; -} -exports.responseToHeadersObject = responseToHeadersObject; -var ErrorResponse = (function () { - function ErrorResponse(statusCode, headers, info) { - this.statusCode = statusCode; - this.headers = headers; - this.info = info; - } - ErrorResponse.fromXHR = function (xhr) { - var errorInfo = xhr.responseText; - try { - errorInfo = JSON.parse(xhr.responseText); - } - catch (e) { - } - return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); - }; - return ErrorResponse; -}()); -exports.ErrorResponse = ErrorResponse; -var NetworkError = (function () { - function NetworkError(error) { - this.error = error; - } - return NetworkError; -}()); -exports.NetworkError = NetworkError; -var XhrReadyState; -(function (XhrReadyState) { - XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; - XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; - XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; - XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; - XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; -})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var LogLevel; -(function (LogLevel) { - LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; - LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; - LogLevel[LogLevel["INFO"] = 3] = "INFO"; - LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; - LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; -})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); -var ConsoleLogger = (function () { - function ConsoleLogger(threshold) { - if (threshold === void 0) { threshold = 2; } - this.threshold = threshold; - var groups = Array(); - var hr = '--------------------------------------------------------------------------------'; - if (!window.console.group) { - window.console.group = function (label) { - groups.push(label); - window.console.log('%c \nBEGIN GROUP: %c', hr, label); - }; - } - if (!window.console.groupEnd) { - window.console.groupEnd = function () { - window.console.log('END GROUP: %c\n%c', groups.pop(), hr); - }; - } - } - ConsoleLogger.prototype.verbose = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.log, LogLevel.VERBOSE, items); - }; - ConsoleLogger.prototype.debug = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.log, LogLevel.DEBUG, items); - }; - ConsoleLogger.prototype.info = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.info, LogLevel.INFO, items); - }; - ConsoleLogger.prototype.warn = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.warn, LogLevel.WARNING, items); - }; - ConsoleLogger.prototype.error = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.error, LogLevel.ERROR, items); - }; - ConsoleLogger.prototype.log = function (logFunction, level, items) { - var _this = this; - if (level >= this.threshold) { - var loggerSignature_1 = "Logger." + LogLevel[level]; - if (items.length > 1) { - window.console.group(); - items.forEach(function (item) { - _this.errorAwareLog(logFunction, item, loggerSignature_1); - }); - window.console.groupEnd(); - } - else { - this.errorAwareLog(logFunction, items[0], loggerSignature_1); - } - } - }; - ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { - if (item.info && item.info.error_uri) { - var errorDesc = item.info.error_description; - var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; - logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); - } - else { - logFunction(loggerSignature + ": ", item); - } - }; - return ConsoleLogger; -}()); -exports.ConsoleLogger = ConsoleLogger; -var EmptyLogger = (function () { - function EmptyLogger() { - } - EmptyLogger.prototype.verbose = function (message, error) { }; - EmptyLogger.prototype.debug = function (message, error) { }; - EmptyLogger.prototype.info = function (message, error) { }; - EmptyLogger.prototype.warn = function (message, error) { }; - EmptyLogger.prototype.error = function (message, error) { }; - return EmptyLogger; -}()); -exports.EmptyLogger = EmptyLogger; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createRetryStrategyOptionsOrDefault = function (options) { - var initialTimeoutMillis = options.initialTimeoutMillis || 1000; - var maxTimeoutMillis = options.maxTimeoutMillis || 5000; - var limit = -1; - if (options.limit !== undefined && options.limit != null) { - limit = options.limit; - } - var increaseTimeout; - if (options.increaseTimeout !== undefined) { - increaseTimeout = options.increaseTimeout; - } - else { - increaseTimeout = function (currentTimeout) { - if (currentTimeout * 2 > maxTimeoutMillis) { - return maxTimeoutMillis; - } - else { - return currentTimeout * 2; - } - }; - } - return { - increaseTimeout: increaseTimeout, - initialTimeoutMillis: initialTimeoutMillis, - limit: limit, - maxTimeoutMillis: maxTimeoutMillis, - }; -}; -var Retry = (function () { - function Retry(waitTimeMillis) { - this.waitTimeMillis = waitTimeMillis; - } - return Retry; -}()); -exports.Retry = Retry; -var DoNotRetry = (function () { - function DoNotRetry(error) { - this.error = error; - } - return DoNotRetry; -}()); -exports.DoNotRetry = DoNotRetry; -var requestMethodIsSafe = function (method) { - method = method.toUpperCase(); - return (method === 'GET' || - method === 'HEAD' || - method === 'OPTIONS' || - method === 'SUBSCRIBE'); -}; -var RetryResolution = (function () { - function RetryResolution(options, logger, retryUnsafeRequests) { - this.options = options; - this.logger = logger; - this.retryUnsafeRequests = retryUnsafeRequests; - this.currentRetryCount = 0; - this.initialTimeoutMillis = options.initialTimeoutMillis; - this.maxTimeoutMillis = options.maxTimeoutMillis; - this.limit = options.limit; - this.increaseTimeoutFunction = options.increaseTimeout; - this.currentBackoffMillis = this.initialTimeoutMillis; - } - RetryResolution.prototype.attemptRetry = function (error) { - this.logger.verbose(this.constructor.name + ": Error received", error); - if (this.currentRetryCount >= this.limit && this.limit >= 0) { - this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); - return new DoNotRetry(error); - } - if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { - this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); - return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); - } - if (error instanceof network_1.NetworkError || - (error instanceof network_1.ErrorResponse && - requestMethodIsSafe(error.headers['Request-Method'])) || - this.retryUnsafeRequests) { - return this.shouldSafeRetry(error); - } - if (error instanceof network_1.NetworkError) { - return this.shouldSafeRetry(error); - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.shouldSafeRetry = function (error) { - if (error instanceof network_1.NetworkError) { - this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); - return new Retry(this.calulateMillisToRetry()); - } - else if (error instanceof network_1.ErrorResponse) { - if (error.statusCode >= 500 && error.statusCode < 600) { - this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); - return new Retry(this.calulateMillisToRetry()); - } - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.calulateMillisToRetry = function () { - this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); - this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); - return this.currentBackoffMillis; - }; - return RetryResolution; -}()); -exports.RetryResolution = RetryResolution; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var logger_1 = __webpack_require__(1); -var request_1 = __webpack_require__(4); -var resuming_subscription_1 = __webpack_require__(5); -var retrying_subscription_1 = __webpack_require__(6); -var subscribe_strategy_1 = __webpack_require__(11); -var subscription_1 = __webpack_require__(12); -var token_providing_subscription_1 = __webpack_require__(7); -var http_1 = __webpack_require__(13); -var websocket_1 = __webpack_require__(14); -var transports_1 = __webpack_require__(8); -var BaseClient = (function () { - function BaseClient(options) { - this.options = options; - this.host = options.host.replace(/(\/)+$/, ''); - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.websocketTransport = new websocket_1.default(this.host); - this.httpTransport = new http_1.default(this.host, options.encrypted); - } - BaseClient.prototype.request = function (options, tokenParams) { - var _this = this; - if (options.tokenProvider) { - return options.tokenProvider - .fetchToken(tokenParams) - .then(function (token) { - if (options.headers !== undefined) { - options.headers['Authorization'] = "Bearer " + token; - } - else { - options.headers = (_a = {}, _a['Authorization'] = "Bearer " + token, _a); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - var _a; - }) - .catch(function (error) { - _this.logger.error(error); - }); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - }; - BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - return BaseClient; -}()); -exports.BaseClient = BaseClient; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -function executeNetworkRequest(createXhr, options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); - sendBody(xhr, options); - }); -} -exports.executeNetworkRequest = executeNetworkRequest; -function sendBody(xhr, options) { - if (options.json) { - xhr.send(JSON.stringify(options.json)); - } - else { - xhr.send(options.body); - } -} -function sendRawRequest(options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(new window.XMLHttpRequest(), resolve, reject); - xhr.open(options.method.toUpperCase(), options.url, true); - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - xhr.send(options.body); - }); -} -exports.sendRawRequest = sendRawRequest; -function attachOnReadyStateChangeHandler(xhr, resolve, reject) { - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status >= 200 && xhr.status < 300) { - resolve(xhr.response); - } - else if (xhr.status !== 0) { - reject(network_1.ErrorResponse.fromXHR(xhr)); - } - else { - reject(new network_1.NetworkError('No Connection')); - } - } - }; - return xhr; -} - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { - var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); - var ResumingSubscription = (function () { - function ResumingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - this.onTransition = onTransition; - var lastEventId = initialEventId; - logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); - if (lastEventId) { - headers['Last-Event-Id'] = lastEventId; - logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); - } - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpeningSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpenSubscriptionState; - }()); - var ResumingSubscriptionState = (function () { - function ResumingSubscriptionState(error, onTransition, lastEventId) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); - var executeSubscriptionOnce = function (error, lastEventId) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = window.setTimeout(function () { - executeNextSubscribeStrategy(lastEventId); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function (lastEventId) { - logger.verbose("ResumingSubscription: trying to re-establish the subscription"); - if (lastEventId) { - logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); - headers['Last-Event-Id'] = lastEventId; - } - _this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - executeSubscriptionOnce(error, lastEventId); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error, lastEventId); - } - ResumingSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - window.clearTimeout(this.timeout); - this.underlyingSubscription.unsubscribe(); - }; - return ResumingSubscriptionState; - }()); - var EndingSubscriptionState = (function () { - function EndingSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); - } - EndingSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription is already ending'); - }; - return EndingSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return ResumingSubscription; - }()); - return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { - var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); - var RetryingSubscription = (function () { - function RetryingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { - return onTransition(new RetryingSubscriptionState(error, onTransition)); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - throw new Error('Method not implemented.'); - }; - return OpeningSubscriptionState; - }()); - var RetryingSubscriptionState = (function () { - function RetryingSubscriptionState(error, onTransition) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); - var executeSubscriptionOnce = function (error) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = window.setTimeout(function () { - executeNextSubscribeStrategy(); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function () { - logger.verbose("RetryingSubscription: trying to re-establish the subscription"); - var underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { return executeSubscriptionOnce(error); }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error); - } - RetryingSubscriptionState.prototype.unsubscribe = function () { - window.clearTimeout(this.timeout); - this.onTransition(new EndedSubscriptionState()); - }; - return RetryingSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - this.onTransition(new EndedSubscriptionState()); - }; - return OpenSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return RetryingSubscription; - }()); - return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { - if (tokenProvider) { - return function (listeners, headers) { - return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); - }; - } - return nextSubscribeStrategy; -}; -var TokenProvidingSubscription = (function () { - function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { - var _this = this; - this.logger = logger; - this.listeners = listeners; - this.headers = headers; - this.tokenProvider = tokenProvider; - this.nextSubscribeStrategy = nextSubscribeStrategy; - this.unsubscribe = function () { - _this.state.unsubscribe(); - _this.state = new InactiveState(_this.logger); - }; - this.state = new ActiveState(logger, headers, nextSubscribeStrategy); - this.subscribe(); - } - TokenProvidingSubscription.prototype.subscribe = function () { - var _this = this; - this.tokenProvider - .fetchToken() - .then(function (token) { - var existingListeners = Object.assign({}, _this.listeners); - _this.state.subscribe(token, { - onEnd: function (error) { - _this.state = new InactiveState(_this.logger); - existingListeners.onEnd(error); - }, - onError: function (error) { - if (_this.isTokenExpiredError(error)) { - _this.tokenProvider.clearToken(token); - _this.subscribe(); - } - else { - _this.state = new InactiveState(_this.logger); - existingListeners.onError(error); - } - }, - onEvent: _this.listeners.onEvent, - onOpen: _this.listeners.onOpen, - }); - }) - .catch(function (error) { - _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); - _this.state = new InactiveState(_this.logger); - _this.listeners.onError(error); - }); - }; - TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { - return (error instanceof network_1.ErrorResponse && - error.statusCode === 401 && - error.info === 'authentication/expired'); - }; - return TokenProvidingSubscription; -}()); -var ActiveState = (function () { - function ActiveState(logger, headers, nextSubscribeStrategy) { - this.logger = logger; - this.headers = headers; - this.nextSubscribeStrategy = nextSubscribeStrategy; - logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); - } - ActiveState.prototype.subscribe = function (token, listeners) { - var _this = this; - this.putTokenIntoHeader(token); - this.underlyingSubscription = this.nextSubscribeStrategy({ - onEnd: function (error) { - _this.logger.verbose("TokenProvidingSubscription: subscription ended"); - listeners.onEnd(error); - }, - onError: function (error) { - _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); - listeners.onError(error); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - _this.logger.verbose("TokenProvidingSubscription: subscription opened"); - listeners.onOpen(headers); - }, - onRetrying: listeners.onRetrying, - }, this.headers); - }; - ActiveState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - }; - ActiveState.prototype.putTokenIntoHeader = function (token) { - this.headers['Authorization'] = "Bearer " + token; - this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); - }; - return ActiveState; -}()); -var InactiveState = (function () { - function InactiveState(logger) { - this.logger = logger; - logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); - } - InactiveState.prototype.subscribe = function (token, listeners) { - this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); - }; - InactiveState.prototype.unsubscribe = function () { - this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); - }; - return InactiveState; -}()); - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createTransportStrategy = function (path, transport, logger) { - return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HOST_BASE = 'pusherplatform.io'; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -exports.BaseClient = base_client_1.BaseClient; -var host_base_1 = __webpack_require__(9); -exports.HOST_BASE = host_base_1.HOST_BASE; -var instance_1 = __webpack_require__(15); -exports.Instance = instance_1.default; -var logger_1 = __webpack_require__(1); -exports.ConsoleLogger = logger_1.ConsoleLogger; -exports.EmptyLogger = logger_1.EmptyLogger; -var network_1 = __webpack_require__(0); -exports.ErrorResponse = network_1.ErrorResponse; -exports.NetworkError = network_1.NetworkError; -exports.responseToHeadersObject = network_1.responseToHeadersObject; -exports.XhrReadyState = network_1.XhrReadyState; -var request_1 = __webpack_require__(4); -exports.executeNetworkRequest = request_1.executeNetworkRequest; -exports.sendRawRequest = request_1.sendRawRequest; -var resuming_subscription_1 = __webpack_require__(5); -exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; -exports.DoNotRetry = retry_strategy_1.DoNotRetry; -exports.Retry = retry_strategy_1.Retry; -exports.RetryResolution = retry_strategy_1.RetryResolution; -var retrying_subscription_1 = __webpack_require__(6); -exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; -var token_providing_subscription_1 = __webpack_require__(7); -exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; -var transports_1 = __webpack_require__(8); -exports.createTransportStrategy = transports_1.createTransportStrategy; -exports.default = { - BaseClient: base_client_1.BaseClient, - ConsoleLogger: logger_1.ConsoleLogger, - EmptyLogger: logger_1.EmptyLogger, - Instance: instance_1.default, -}; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { - return { - onEnd: subListeners.onEnd, - onError: subListeners.onError, - onEvent: subListeners.onEvent, - onOpen: subListeners.onOpen, - onRetrying: subListeners.onRetrying, - }; -}; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.replaceMissingListenersWithNoOps = function (listeners) { - var onEndNoOp = function (error) { }; - var onEnd = listeners.onEnd || onEndNoOp; - var onErrorNoOp = function (error) { }; - var onError = listeners.onError || onErrorNoOp; - var onEventNoOp = function (event) { }; - var onEvent = listeners.onEvent || onEventNoOp; - var onOpenNoOp = function (headers) { }; - var onOpen = listeners.onOpen || onOpenNoOp; - var onRetryingNoOp = function () { }; - var onRetrying = listeners.onRetrying || onRetryingNoOp; - var onSubscribeNoOp = function () { }; - var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; - return { - onEnd: onEnd, - onError: onError, - onEvent: onEvent, - onOpen: onOpen, - onRetrying: onRetrying, - onSubscribe: onSubscribe, - }; -}; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var HttpTransportState; -(function (HttpTransportState) { - HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; - HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; - HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; - HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; - HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; -})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); -var HttpSubscription = (function () { - function HttpSubscription(xhr, listeners) { - var _this = this; - this.gotEOS = false; - this.lastNewlineIndex = 0; - this.state = HttpTransportState.UNOPENED; - this.xhr = xhr; - this.listeners = listeners; - this.xhr.onreadystatechange = function () { - switch (_this.xhr.readyState) { - case network_1.XhrReadyState.UNSENT: - case network_1.XhrReadyState.OPENED: - case network_1.XhrReadyState.HEADERS_RECEIVED: - _this.assertStateIsIn(HttpTransportState.OPENING); - break; - case network_1.XhrReadyState.LOADING: - _this.onLoading(); - break; - case network_1.XhrReadyState.DONE: - _this.onDone(); - break; - } - }; - this.state = HttpTransportState.OPENING; - this.xhr.send(); - return this; - } - HttpSubscription.prototype.unsubscribe = function () { - this.state = HttpTransportState.ENDED; - this.xhr.abort(); - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - }; - HttpSubscription.prototype.onLoading = function () { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - window.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN); - var err = this.onChunk(); - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - if (err) { - this.state = HttpTransportState.ENDED; - if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else { - } - } - }; - HttpSubscription.prototype.onDone = function () { - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - var err = this.onChunk(); - if (err) { - this.state = HttpTransportState.ENDED; - if (err.statusCode === 204) { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else if (this.state <= HttpTransportState.ENDING) { - if (this.listeners.onError) { - this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); - } - } - else { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - } - else { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); - if (this.state === HttpTransportState.ENDED) { - return; - } - else if (this.xhr.status === 0) { - if (this.listeners.onError) { - this.listeners.onError(new network_1.NetworkError('Connection lost.')); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); - } - } - } - }; - HttpSubscription.prototype.onChunk = function () { - this.assertStateIsIn(HttpTransportState.OPEN); - var response = this.xhr.responseText; - var newlineIndex = response.lastIndexOf('\n'); - if (newlineIndex > this.lastNewlineIndex) { - var rawEvents = response - .slice(this.lastNewlineIndex, newlineIndex) - .split('\n'); - this.lastNewlineIndex = newlineIndex; - for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { - var rawEvent = rawEvents_1[_i]; - if (rawEvent.length === 0) { - continue; - } - var data = JSON.parse(rawEvent); - var err = this.onMessage(data); - if (err != null) { - return err; - } - } - } - }; - HttpSubscription.prototype.assertStateIsIn = function () { - var _this = this; - var validStates = []; - for (var _i = 0; _i < arguments.length; _i++) { - validStates[_i] = arguments[_i]; - } - var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); - if (!stateIsValid) { - var expectedStates = validStates - .map(function (state) { return HttpTransportState[state]; }) - .join(', '); - var actualState = HttpTransportState[this.state]; - window.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); - } - }; - HttpSubscription.prototype.onMessage = function (message) { - this.assertStateIsIn(HttpTransportState.OPEN); - this.verifyMessage(message); - switch (message[0]) { - case 0: - return null; - case 1: - return this.onEventMessage(message); - case 255: - return this.onEOSMessage(message); - default: - return new Error('Unknown Message: ' + JSON.stringify(message)); - } - }; - HttpSubscription.prototype.onEventMessage = function (eventMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eventMessage.length !== 4) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; - if (typeof id !== 'string') { - return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); - } - if (this.listeners.onEvent) { - this.listeners.onEvent({ body: body, headers: headers, eventId: id }); - } - return null; - }; - HttpSubscription.prototype.onEOSMessage = function (eosMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eosMessage.length !== 4) { - return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); - } - var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; - if (typeof statusCode !== 'number') { - return new Error('Invalid EOS Status Code'); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid EOS ElementsHeaders'); - } - this.state = HttpTransportState.ENDING; - return new network_1.ErrorResponse(statusCode, headers, info); - }; - HttpSubscription.prototype.verifyMessage = function (message) { - if (this.gotEOS) { - return new Error('Got another message after EOS message'); - } - if (!Array.isArray(message)) { - return new Error('Message is not an array'); - } - if (message.length < 1) { - return new Error('Message is empty array'); - } - }; - return HttpSubscription; -}()); -var HttpTransport = (function () { - function HttpTransport(host, encrypted) { - if (encrypted === void 0) { encrypted = true; } - this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; - } - HttpTransport.prototype.request = function (requestOptions) { - return this.createXHR(this.baseURL, requestOptions); - }; - HttpTransport.prototype.subscribe = function (path, listeners, headers) { - var requestOptions = { - headers: headers, - method: 'SUBSCRIBE', - path: path, - }; - return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); - }; - HttpTransport.prototype.createXHR = function (baseURL, options) { - var xhr = new window.XMLHttpRequest(); - var path = options.path.replace(/^\/+/, ''); - var endpoint = baseURL + "/" + path; - xhr.open(options.method.toUpperCase(), endpoint, true); - xhr = this.setJSONHeaderIfAppropriate(xhr, options); - if (options.jwt) { - xhr.setRequestHeader('authorization', "Bearer " + options.jwt); - } - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - return xhr; - }; - HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { - if (options.json) { - xhr.setRequestHeader('content-type', 'application/json'); - } - return xhr; - }; - return HttpTransport; -}()); -exports.default = HttpTransport; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var SubscribeMessageType = 100; -var OpenMessageType = 101; -var EventMessageType = 102; -var UnsubscribeMessageType = 198; -var EosMessageType = 199; -var PingMessageType = 16; -var PongMessageType = 17; -var CloseMessageType = 99; -var WSReadyState; -(function (WSReadyState) { - WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; - WSReadyState[WSReadyState["Open"] = 1] = "Open"; - WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; - WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; -})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); -var WsSubscriptions = (function () { - function WsSubscriptions() { - this.subscriptions = {}; - } - WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { - this.subscriptions[subID] = { - headers: headers, - listeners: listeners, - path: path, - }; - return subID; - }; - WsSubscriptions.prototype.has = function (subID) { - return this.subscriptions[subID] !== undefined; - }; - WsSubscriptions.prototype.isEmpty = function () { - return Object.keys(this.subscriptions).length === 0; - }; - WsSubscriptions.prototype.remove = function (subID) { - return delete this.subscriptions[subID]; - }; - WsSubscriptions.prototype.get = function (subID) { - return this.subscriptions[subID]; - }; - WsSubscriptions.prototype.getAll = function () { - return this.subscriptions; - }; - WsSubscriptions.prototype.getAllAsArray = function () { - var _this = this; - return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); - }; - WsSubscriptions.prototype.removeAll = function () { - this.subscriptions = {}; - }; - return WsSubscriptions; -}()); -var WsSubscription = (function () { - function WsSubscription(wsTransport, subID) { - this.wsTransport = wsTransport; - this.subID = subID; - } - WsSubscription.prototype.unsubscribe = function () { - this.wsTransport.unsubscribe(this.subID); - }; - return WsSubscription; -}()); -var pingIntervalMs = 30000; -var pingTimeoutMs = 10000; -var WebSocketTransport = (function () { - function WebSocketTransport(host) { - this.webSocketPath = '/ws'; - this.forcedClose = false; - this.closedError = null; - this.baseURL = "wss://" + host + this.webSocketPath; - this.lastSubscriptionID = 0; - this.subscriptions = new WsSubscriptions(); - this.pendingSubscriptions = new WsSubscriptions(); - this.connect(); - } - WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { - this.tryReconnectIfNeeded(); - var subID = this.lastSubscriptionID++; - if (this.socket.readyState !== WSReadyState.Open) { - this.pendingSubscriptions.add(subID, path, listeners, headers); - return new WsSubscription(this, subID); - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - return new WsSubscription(this, subID); - }; - WebSocketTransport.prototype.unsubscribe = function (subID) { - this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); - var subscription = this.subscriptions.get(subID); - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - this.subscriptions.remove(subID); - }; - WebSocketTransport.prototype.connect = function () { - var _this = this; - this.close(); - this.forcedClose = false; - this.closedError = null; - this.socket = new window.WebSocket(this.baseURL); - this.socket.onopen = function (event) { - var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); - allPendingSubscriptions.forEach(function (subscription) { - var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; - _this.subscribePending(path, listeners, headers, subID); - }); - _this.pendingSubscriptions.removeAll(); - _this.pingInterval = window.setInterval(function () { - if (_this.pongTimeout) { - return; - } - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - return; - } - _this.sendMessage(_this.getMessage(PingMessageType, now)); - _this.lastSentPingID = now; - _this.pongTimeout = window.setTimeout(function () { - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - _this.pongTimeout = null; - return; - } - _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); - }, pingTimeoutMs); - }, pingIntervalMs); - }; - this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; - this.socket.onerror = function (event) { - _this.close(new network_1.NetworkError('Connection was lost.')); - }; - this.socket.onclose = function (event) { - if (!_this.forcedClose) { - _this.tryReconnectIfNeeded(); - return; - } - var callback = _this.closedError - ? function (subscription) { - if (subscription.listeners.onError) { - subscription.listeners.onError(_this.closedError); - } - } - : function (subscription) { - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - }; - var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false - ? _this.pendingSubscriptions - : _this.subscriptions; - allSubscriptions.getAllAsArray().forEach(callback); - allSubscriptions.removeAll(); - if (_this.closedError) { - _this.tryReconnectIfNeeded(); - } - }; - }; - WebSocketTransport.prototype.close = function (error) { - if (!(this.socket instanceof window.WebSocket)) { - return; - } - this.forcedClose = true; - this.closedError = error; - this.socket.close(); - window.clearTimeout(this.pingInterval); - window.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.tryReconnectIfNeeded = function () { - if (this.socket.readyState !== WSReadyState.Closed) { - return; - } - this.connect(); - }; - WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { - if (subID === undefined) { - window.console.logger.debug("Subscription to path " + path + " has an undefined ID"); - return; - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - }; - WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { - return [messageType, id, path, headers]; - }; - WebSocketTransport.prototype.sendMessage = function (message) { - if (this.socket.readyState !== WSReadyState.Open) { - return window.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); - } - this.socket.send(JSON.stringify(message)); - }; - WebSocketTransport.prototype.subscription = function (subID) { - return this.subscriptions.get(subID); - }; - WebSocketTransport.prototype.receiveMessage = function (event) { - this.lastMessageReceivedTimestamp = new Date().getTime(); - var message; - try { - message = JSON.parse(event.data); - } - catch (err) { - this.close(new Error("Message is not valid JSON format. Getting " + event.data)); - return; - } - var nonValidMessageError = this.validateMessage(message); - if (nonValidMessageError) { - this.close(new Error(nonValidMessageError.message)); - return; - } - var messageType = message.shift(); - switch (messageType) { - case PongMessageType: - this.onPongMessage(message); - return; - case PingMessageType: - this.onPingMessage(message); - return; - case CloseMessageType: - this.onCloseMessage(message); - return; - } - var subID = message.shift(); - var subscription = this.subscription(subID); - if (!subscription) { - this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); - return; - } - var listeners = subscription.listeners; - switch (messageType) { - case OpenMessageType: - this.onOpenMessage(message, subID, listeners); - break; - case EventMessageType: - this.onEventMessage(message, listeners); - break; - case EosMessageType: - this.onEOSMessage(message, subID, listeners); - break; - default: - this.close(new Error('Received non existing type of message.')); - } - }; - WebSocketTransport.prototype.validateMessage = function (message) { - if (!Array.isArray(message)) { - return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); - } - if (message.length < 1) { - return new Error("Message is empty array: " + JSON.stringify(message)); - } - return null; - }; - WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { - if (subscriptionListeners.onOpen) { - subscriptionListeners.onOpen(message[1]); - } - }; - WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { - if (eventMessage.length !== 3) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; - if (typeof eventId !== 'string') { - return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); - } - if (subscriptionListeners.onEvent) { - subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); - } - }; - WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { - this.subscriptions.remove(subID); - if (eosMessage.length !== 3) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); - } - return; - } - var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; - if (typeof statusCode !== 'number') { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS Status Code')); - } - return; - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); - } - return; - } - if (statusCode === 204) { - if (subscriptionListeners.onEnd) { - subscriptionListeners.onEnd(null); - } - return; - } - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); - } - return; - }; - WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { - var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; - if (typeof statusCode !== 'number') { - return this.close(new Error('Close message: Invalid EOS Status Code')); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); - } - this.close(); - }; - WebSocketTransport.prototype.onPongMessage = function (message) { - var receviedPongID = message[0]; - if (this.lastSentPingID !== receviedPongID) { - this.close(new network_1.NetworkError("Didn't received pong with proper ID")); - } - window.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.onPingMessage = function (message) { - var receviedPingID = message[0]; - this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); - }; - return WebSocketTransport; -}()); -exports.default = WebSocketTransport; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -var host_base_1 = __webpack_require__(9); -var logger_1 = __webpack_require__(1); -var Instance = (function () { - function Instance(options) { - if (!options.locator) { - throw new Error('Expected `locator` property in Instance options!'); - } - var splitInstanceLocator = options.locator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instance locator property is in the wrong format!'); - } - if (!options.serviceName) { - throw new Error('Expected `serviceName` property in Instance options!'); - } - if (!options.serviceVersion) { - throw new Error('Expected `serviceVersion` property in Instance otpions!'); - } - this.platformVersion = splitInstanceLocator[0]; - this.cluster = splitInstanceLocator[1]; - this.id = splitInstanceLocator[2]; - this.serviceName = options.serviceName; - this.serviceVersion = options.serviceVersion; - this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.client = - options.client || - new base_client_1.BaseClient({ - encrypted: options.encrypted, - host: this.host, - logger: this.logger, - }); - this.tokenProvider = options.tokenProvider; - } - Instance.prototype.request = function (options, tokenParams) { - options.path = this.absPath(options.path); - if (options.headers == null || options.headers === undefined) { - options.headers = {}; - } - options.tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.request(options, tokenParams); - }; - Instance.prototype.subscribeNonResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); - }; - Instance.prototype.subscribeResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); - }; - Instance.prototype.absPath = function (relativePath) { - return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) - .replace(/\/+/g, '/') - .replace(/\/+$/, ''); - }; - return Instance; -}()); -exports.default = Instance; - - -/***/ }) -/******/ ]); -}); -}); - -unwrapExports(pusherPlatform); -var pusherPlatform_1 = pusherPlatform.BaseClient; -var pusherPlatform_2 = pusherPlatform.HOST_BASE; -var pusherPlatform_3 = pusherPlatform.Instance; -var pusherPlatform_4 = pusherPlatform.sendRawRequest; - -function _isPlaceholder(a) { - return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true; -} - -/** - * Optimized internal one-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry1(fn) { - return function f1(a) { - if (arguments.length === 0 || _isPlaceholder(a)) { - return f1; - } else { - return fn.apply(this, arguments); - } - }; -} - -/** - * Returns a function that always returns the given value. Note that for - * non-primitives the value returned is a reference to the original value. - * - * This function is known as `const`, `constant`, or `K` (for K combinator) in - * other languages and libraries. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig a -> (* -> a) - * @param {*} val The value to wrap in a function - * @return {Function} A Function :: * -> val. - * @example - * - * var t = R.always('Tee'); - * t(); //=> 'Tee' - */ -var always = /*#__PURE__*/_curry1(function always(val) { - return function () { - return val; - }; -}); - -/** - * A function that always returns `false`. Any passed in parameters are ignored. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig * -> Boolean - * @param {*} - * @return {Boolean} - * @see R.always, R.T - * @example - * - * R.F(); //=> false - */ -var F = /*#__PURE__*/always(false); - -/** - * A function that always returns `true`. Any passed in parameters are ignored. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig * -> Boolean - * @param {*} - * @return {Boolean} - * @see R.always, R.F - * @example - * - * R.T(); //=> true - */ -var T = /*#__PURE__*/always(true); - -/** - * A special placeholder value used to specify "gaps" within curried functions, - * allowing partial application of any combination of arguments, regardless of - * their positions. - * - * If `g` is a curried ternary function and `_` is `R.__`, the following are - * equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2, _)(1, 3)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @constant - * @memberOf R - * @since v0.6.0 - * @category Function - * @example - * - * var greet = R.replace('{name}', R.__, 'Hello, {name}!'); - * greet('Alice'); //=> 'Hello, Alice!' - */ - -/** - * Optimized internal two-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry2(fn) { - return function f2(a, b) { - switch (arguments.length) { - case 0: - return f2; - case 1: - return _isPlaceholder(a) ? f2 : _curry1(function (_b) { - return fn(a, _b); - }); - default: - return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) { - return fn(_a, b); - }) : _isPlaceholder(b) ? _curry1(function (_b) { - return fn(a, _b); - }) : fn(a, b); - } - }; -} - -/** - * Adds two values. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig Number -> Number -> Number - * @param {Number} a - * @param {Number} b - * @return {Number} - * @see R.subtract - * @example - * - * R.add(2, 3); //=> 5 - * R.add(7)(10); //=> 17 - */ -var add = /*#__PURE__*/_curry2(function add(a, b) { - return Number(a) + Number(b); -}); - -/** - * Private `concat` function to merge two array-like objects. - * - * @private - * @param {Array|Arguments} [set1=[]] An array-like object. - * @param {Array|Arguments} [set2=[]] An array-like object. - * @return {Array} A new, merged array. - * @example - * - * _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] - */ -function _concat(set1, set2) { - set1 = set1 || []; - set2 = set2 || []; - var idx; - var len1 = set1.length; - var len2 = set2.length; - var result = []; - - idx = 0; - while (idx < len1) { - result[result.length] = set1[idx]; - idx += 1; - } - idx = 0; - while (idx < len2) { - result[result.length] = set2[idx]; - idx += 1; - } - return result; -} - -function _arity(n, fn) { - /* eslint-disable no-unused-vars */ - switch (n) { - case 0: - return function () { - return fn.apply(this, arguments); - }; - case 1: - return function (a0) { - return fn.apply(this, arguments); - }; - case 2: - return function (a0, a1) { - return fn.apply(this, arguments); - }; - case 3: - return function (a0, a1, a2) { - return fn.apply(this, arguments); - }; - case 4: - return function (a0, a1, a2, a3) { - return fn.apply(this, arguments); - }; - case 5: - return function (a0, a1, a2, a3, a4) { - return fn.apply(this, arguments); - }; - case 6: - return function (a0, a1, a2, a3, a4, a5) { - return fn.apply(this, arguments); - }; - case 7: - return function (a0, a1, a2, a3, a4, a5, a6) { - return fn.apply(this, arguments); - }; - case 8: - return function (a0, a1, a2, a3, a4, a5, a6, a7) { - return fn.apply(this, arguments); - }; - case 9: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { - return fn.apply(this, arguments); - }; - case 10: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { - return fn.apply(this, arguments); - }; - default: - throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); - } -} - -/** - * Internal curryN function. - * - * @private - * @category Function - * @param {Number} length The arity of the curried function. - * @param {Array} received An array of arguments received thus far. - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curryN(length, received, fn) { - return function () { - var combined = []; - var argsIdx = 0; - var left = length; - var combinedIdx = 0; - while (combinedIdx < received.length || argsIdx < arguments.length) { - var result; - if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { - result = received[combinedIdx]; - } else { - result = arguments[argsIdx]; - argsIdx += 1; - } - combined[combinedIdx] = result; - if (!_isPlaceholder(result)) { - left -= 1; - } - combinedIdx += 1; - } - return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); - }; -} - -/** - * Returns a curried equivalent of the provided function, with the specified - * arity. The curried function has two unusual capabilities. First, its - * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the - * following are equivalent: - * - * - `g(1)(2)(3)` - * - `g(1)(2, 3)` - * - `g(1, 2)(3)` - * - `g(1, 2, 3)` - * - * Secondly, the special placeholder value [`R.__`](#__) may be used to specify - * "gaps", allowing partial application of any combination of arguments, - * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), - * the following are equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @func - * @memberOf R - * @since v0.5.0 - * @category Function - * @sig Number -> (* -> a) -> (* -> a) - * @param {Number} length The arity for the returned function. - * @param {Function} fn The function to curry. - * @return {Function} A new, curried function. - * @see R.curry - * @example - * - * var sumArgs = (...args) => R.sum(args); - * - * var curriedAddFourNumbers = R.curryN(4, sumArgs); - * var f = curriedAddFourNumbers(1, 2); - * var g = f(3); - * g(4); //=> 10 - */ -var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) { - if (length === 1) { - return _curry1(fn); - } - return _arity(length, _curryN(length, [], fn)); -}); - -/** - * Optimized internal three-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry3(fn) { - return function f3(a, b, c) { - switch (arguments.length) { - case 0: - return f3; - case 1: - return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) { - return fn(a, _b, _c); - }); - case 2: - return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) { - return fn(_a, b, _c); - }) : _isPlaceholder(b) ? _curry2(function (_b, _c) { - return fn(a, _b, _c); - }) : _curry1(function (_c) { - return fn(a, b, _c); - }); - default: - return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) { - return fn(_a, _b, c); - }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) { - return fn(_a, b, _c); - }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) { - return fn(a, _b, _c); - }) : _isPlaceholder(a) ? _curry1(function (_a) { - return fn(_a, b, c); - }) : _isPlaceholder(b) ? _curry1(function (_b) { - return fn(a, _b, c); - }) : _isPlaceholder(c) ? _curry1(function (_c) { - return fn(a, b, _c); - }) : fn(a, b, c); - } - }; -} - -/** - * Tests whether or not an object is an array. - * - * @private - * @param {*} val The object to test. - * @return {Boolean} `true` if `val` is an array, `false` otherwise. - * @example - * - * _isArray([]); //=> true - * _isArray(null); //=> false - * _isArray({}); //=> false - */ -var _isArray = Array.isArray || function _isArray(val) { - return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]'; -}; - -function _isTransformer(obj) { - return typeof obj['@@transducer/step'] === 'function'; -} - -/** - * Returns a function that dispatches with different strategies based on the - * object in list position (last argument). If it is an array, executes [fn]. - * Otherwise, if it has a function with one of the given method names, it will - * execute that function (functor case). Otherwise, if it is a transformer, - * uses transducer [xf] to return a new transformer (transducer case). - * Otherwise, it will default to executing [fn]. - * - * @private - * @param {Array} methodNames properties to check for a custom implementation - * @param {Function} xf transducer to initialize if object is transformer - * @param {Function} fn default ramda implementation - * @return {Function} A function that dispatches on object in list position - */ -function _dispatchable(methodNames, xf, fn) { - return function () { - if (arguments.length === 0) { - return fn(); - } - var args = Array.prototype.slice.call(arguments, 0); - var obj = args.pop(); - if (!_isArray(obj)) { - var idx = 0; - while (idx < methodNames.length) { - if (typeof obj[methodNames[idx]] === 'function') { - return obj[methodNames[idx]].apply(obj, args); - } - idx += 1; - } - if (_isTransformer(obj)) { - var transducer = xf.apply(null, args); - return transducer(obj); - } - } - return fn.apply(this, arguments); - }; -} - -var _xfBase = { - init: function () { - return this.xf['@@transducer/init'](); - }, - result: function (result) { - return this.xf['@@transducer/result'](result); - } -}; - -/** - * Returns the larger of its two arguments. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig Ord a => a -> a -> a - * @param {*} a - * @param {*} b - * @return {*} - * @see R.maxBy, R.min - * @example - * - * R.max(789, 123); //=> 789 - * R.max('a', 'b'); //=> 'b' - */ -var max = /*#__PURE__*/_curry2(function max(a, b) { - return b > a ? b : a; -}); - -function _map(fn, functor) { - var idx = 0; - var len = functor.length; - var result = Array(len); - while (idx < len) { - result[idx] = fn(functor[idx]); - idx += 1; - } - return result; -} - -function _isString(x) { - return Object.prototype.toString.call(x) === '[object String]'; -} - -/** - * Tests whether or not an object is similar to an array. - * - * @private - * @category Type - * @category List - * @sig * -> Boolean - * @param {*} x The object to test. - * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise. - * @example - * - * _isArrayLike([]); //=> true - * _isArrayLike(true); //=> false - * _isArrayLike({}); //=> false - * _isArrayLike({length: 10}); //=> false - * _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true - */ -var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) { - if (_isArray(x)) { - return true; - } - if (!x) { - return false; - } - if (typeof x !== 'object') { - return false; - } - if (_isString(x)) { - return false; - } - if (x.nodeType === 1) { - return !!x.length; - } - if (x.length === 0) { - return true; - } - if (x.length > 0) { - return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); - } - return false; -}); - -var XWrap = /*#__PURE__*/function () { - function XWrap(fn) { - this.f = fn; - } - XWrap.prototype['@@transducer/init'] = function () { - throw new Error('init not implemented on XWrap'); - }; - XWrap.prototype['@@transducer/result'] = function (acc) { - return acc; - }; - XWrap.prototype['@@transducer/step'] = function (acc, x) { - return this.f(acc, x); - }; - - return XWrap; -}(); - -function _xwrap(fn) { - return new XWrap(fn); -} - -/** - * Creates a function that is bound to a context. - * Note: `R.bind` does not provide the additional argument-binding capabilities of - * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). - * - * @func - * @memberOf R - * @since v0.6.0 - * @category Function - * @category Object - * @sig (* -> *) -> {*} -> (* -> *) - * @param {Function} fn The function to bind to context - * @param {Object} thisObj The context to bind `fn` to - * @return {Function} A function that will execute in the context of `thisObj`. - * @see R.partial - * @example - * - * var log = R.bind(console.log, console); - * R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3} - * // logs {a: 2} - * @symb R.bind(f, o)(a, b) = f.call(o, a, b) - */ -var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) { - return _arity(fn.length, function () { - return fn.apply(thisObj, arguments); - }); -}); - -function _arrayReduce(xf, acc, list) { - var idx = 0; - var len = list.length; - while (idx < len) { - acc = xf['@@transducer/step'](acc, list[idx]); - if (acc && acc['@@transducer/reduced']) { - acc = acc['@@transducer/value']; - break; - } - idx += 1; - } - return xf['@@transducer/result'](acc); -} - -function _iterableReduce(xf, acc, iter) { - var step = iter.next(); - while (!step.done) { - acc = xf['@@transducer/step'](acc, step.value); - if (acc && acc['@@transducer/reduced']) { - acc = acc['@@transducer/value']; - break; - } - step = iter.next(); - } - return xf['@@transducer/result'](acc); -} - -function _methodReduce(xf, acc, obj, methodName) { - return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc)); -} - -var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator'; - -function _reduce(fn, acc, list) { - if (typeof fn === 'function') { - fn = _xwrap(fn); - } - if (_isArrayLike(list)) { - return _arrayReduce(fn, acc, list); - } - if (typeof list['fantasy-land/reduce'] === 'function') { - return _methodReduce(fn, acc, list, 'fantasy-land/reduce'); - } - if (list[symIterator] != null) { - return _iterableReduce(fn, acc, list[symIterator]()); - } - if (typeof list.next === 'function') { - return _iterableReduce(fn, acc, list); - } - if (typeof list.reduce === 'function') { - return _methodReduce(fn, acc, list, 'reduce'); - } - - throw new TypeError('reduce: list must be array or iterable'); -} - -var XMap = /*#__PURE__*/function () { - function XMap(f, xf) { - this.xf = xf; - this.f = f; - } - XMap.prototype['@@transducer/init'] = _xfBase.init; - XMap.prototype['@@transducer/result'] = _xfBase.result; - XMap.prototype['@@transducer/step'] = function (result, input) { - return this.xf['@@transducer/step'](result, this.f(input)); - }; - - return XMap; -}(); - -var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) { - return new XMap(f, xf); -}); - -function _has(prop, obj) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -var toString = Object.prototype.toString; -var _isArguments = function () { - return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) { - return toString.call(x) === '[object Arguments]'; - } : function _isArguments(x) { - return _has('callee', x); - }; -}; - -// cover IE < 9 keys issues -var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString'); -var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; -// Safari bug -var hasArgsEnumBug = /*#__PURE__*/function () { - return arguments.propertyIsEnumerable('length'); -}(); - -var contains = function contains(list, item) { - var idx = 0; - while (idx < list.length) { - if (list[idx] === item) { - return true; - } - idx += 1; - } - return false; -}; - -/** - * Returns a list containing the names of all the enumerable own properties of - * the supplied object. - * Note that the order of the output array is not guaranteed to be consistent - * across different JS platforms. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {k: v} -> [k] - * @param {Object} obj The object to extract properties from - * @return {Array} An array of the object's own properties. - * @see R.keysIn, R.values - * @example - * - * R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c'] - */ -var _keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? function keys(obj) { - return Object(obj) !== obj ? [] : Object.keys(obj); -} : function keys(obj) { - if (Object(obj) !== obj) { - return []; - } - var prop, nIdx; - var ks = []; - var checkArgsLength = hasArgsEnumBug && _isArguments(obj); - for (prop in obj) { - if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) { - ks[ks.length] = prop; - } - } - if (hasEnumBug) { - nIdx = nonEnumerableProps.length - 1; - while (nIdx >= 0) { - prop = nonEnumerableProps[nIdx]; - if (_has(prop, obj) && !contains(ks, prop)) { - ks[ks.length] = prop; - } - nIdx -= 1; - } - } - return ks; -}; -var keys = /*#__PURE__*/_curry1(_keys); - -/** - * Takes a function and - * a [functor](https://github.com/fantasyland/fantasy-land#functor), - * applies the function to each of the functor's values, and returns - * a functor of the same shape. - * - * Ramda provides suitable `map` implementations for `Array` and `Object`, - * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`. - * - * Dispatches to the `map` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * Also treats functions as functors and will compose them together. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Functor f => (a -> b) -> f a -> f b - * @param {Function} fn The function to be called on every element of the input `list`. - * @param {Array} list The list to be iterated over. - * @return {Array} The new list. - * @see R.transduce, R.addIndex - * @example - * - * var double = x => x * 2; - * - * R.map(double, [1, 2, 3]); //=> [2, 4, 6] - * - * R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6} - * @symb R.map(f, [a, b]) = [f(a), f(b)] - * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) } - * @symb R.map(f, functor_o) = functor_o.map(f) - */ -var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) { - switch (Object.prototype.toString.call(functor)) { - case '[object Function]': - return curryN(functor.length, function () { - return fn.call(this, functor.apply(this, arguments)); - }); - case '[object Object]': - return _reduce(function (acc, key) { - acc[key] = fn(functor[key]); - return acc; - }, {}, keys(functor)); - default: - return _map(fn, functor); - } -})); - -/** - * Retrieve the value at a given path. - * - * @func - * @memberOf R - * @since v0.2.0 - * @category Object - * @typedefn Idx = String | Int - * @sig [Idx] -> {a} -> a | Undefined - * @param {Array} path The path to use. - * @param {Object} obj The object to retrieve the nested property from. - * @return {*} The data at `path`. - * @see R.prop - * @example - * - * R.path(['a', 'b'], {a: {b: 2}}); //=> 2 - * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined - */ -var path = /*#__PURE__*/_curry2(function path(paths, obj) { - var val = obj; - var idx = 0; - while (idx < paths.length) { - if (val == null) { - return; - } - val = val[paths[idx]]; - idx += 1; - } - return val; -}); - -/** - * Returns a function that when supplied an object returns the indicated - * property of that object, if it exists. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig s -> {s: a} -> a | Undefined - * @param {String} p The property name - * @param {Object} obj The object to query - * @return {*} The value at `obj.p`. - * @see R.path - * @example - * - * R.prop('x', {x: 100}); //=> 100 - * R.prop('x', {}); //=> undefined - */ - -var prop = /*#__PURE__*/_curry2(function prop(p, obj) { - return path([p], obj); -}); - -/** - * Returns a new list by plucking the same named property off all objects in - * the list supplied. - * - * `pluck` will work on - * any [functor](https://github.com/fantasyland/fantasy-land#functor) in - * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Functor f => k -> f {k: v} -> f v - * @param {Number|String} key The key name to pluck off of each object. - * @param {Array} f The array or functor to consider. - * @return {Array} The list of values for the given key. - * @see R.props - * @example - * - * R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2] - * R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3] - * R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5} - * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5] - * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5] - */ -var pluck = /*#__PURE__*/_curry2(function pluck(p, list) { - return map(prop(p), list); -}); - -/** - * Returns a single item by iterating through the list, successively calling - * the iterator function and passing it an accumulator value and the current - * value from the array, and then passing the result to the next call. - * - * The iterator function receives two values: *(acc, value)*. It may use - * [`R.reduced`](#reduced) to shortcut the iteration. - * - * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function - * is *(value, acc)*. - * - * Note: `R.reduce` does not skip deleted or unassigned indices (sparse - * arrays), unlike the native `Array.prototype.reduce` method. For more details - * on this behavior, see: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description - * - * Dispatches to the `reduce` method of the third argument, if present. When - * doing so, it is up to the user to handle the [`R.reduced`](#reduced) - * shortcuting, as this is not implemented by `reduce`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig ((a, b) -> a) -> a -> [b] -> a - * @param {Function} fn The iterator function. Receives two values, the accumulator and the - * current element from the array. - * @param {*} acc The accumulator value. - * @param {Array} list The list to iterate over. - * @return {*} The final, accumulated value. - * @see R.reduced, R.addIndex, R.reduceRight - * @example - * - * R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10 - * // - -10 - * // / \ / \ - * // - 4 -6 4 - * // / \ / \ - * // - 3 ==> -3 3 - * // / \ / \ - * // - 2 -1 2 - * // / \ / \ - * // 0 1 0 1 - * - * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d) - */ -var reduce = /*#__PURE__*/_curry3(_reduce); - -/** - * ap applies a list of functions to a list of values. - * - * Dispatches to the `ap` method of the second argument, if present. Also - * treats curried functions as applicatives. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category Function - * @sig [a -> b] -> [a] -> [b] - * @sig Apply f => f (a -> b) -> f a -> f b - * @sig (a -> b -> c) -> (a -> b) -> (a -> c) - * @param {*} applyF - * @param {*} applyX - * @return {*} - * @example - * - * R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6] - * R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"] - * - * // R.ap can also be used as S combinator - * // when only two functions are passed - * R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA' - * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)] - */ -var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) { - return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) { - return applyF(x)(applyX(x)); - } : - // else - _reduce(function (acc, f) { - return _concat(acc, map(f, applyX)); - }, [], applyF); -}); - -/** - * Returns a new list containing the contents of the given list, followed by - * the given element. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig a -> [a] -> [a] - * @param {*} el The element to add to the end of the new list. - * @param {Array} list The list of elements to add a new item to. - * list. - * @return {Array} A new list containing the elements of the old list followed by `el`. - * @see R.prepend - * @example - * - * R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests'] - * R.append('tests', []); //=> ['tests'] - * R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']] - */ -var append = /*#__PURE__*/_curry2(function append(el, list) { - return _concat(list, [el]); -}); - -/** - * Returns a list of all the enumerable own properties of the supplied object. - * Note that the order of the output array is not guaranteed across different - * JS platforms. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {k: v} -> [v] - * @param {Object} obj The object to extract values from - * @return {Array} An array of the values of the object's own properties. - * @see R.valuesIn, R.keys - * @example - * - * R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3] - */ -var values = /*#__PURE__*/_curry1(function values(obj) { - var props = keys(obj); - var len = props.length; - var vals = []; - var idx = 0; - while (idx < len) { - vals[idx] = obj[props[idx]]; - idx += 1; - } - return vals; -}); - -/** - * Determine if the passed argument is an integer. - * - * @private - * @param {*} n - * @category Type - * @return {Boolean} - */ - -function _isFunction(x) { - return Object.prototype.toString.call(x) === '[object Function]'; -} - -/** - * "lifts" a function to be the specified arity, so that it may "map over" that - * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). - * - * @func - * @memberOf R - * @since v0.7.0 - * @category Function - * @sig Number -> (*... -> *) -> ([*]... -> [*]) - * @param {Function} fn The function to lift into higher context - * @return {Function} The lifted function. - * @see R.lift, R.ap - * @example - * - * var madd3 = R.liftN(3, (...args) => R.sum(args)); - * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] - */ -var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) { - var lifted = curryN(arity, fn); - return curryN(arity, function () { - return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1)); - }); -}); - -/** - * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other - * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). - * - * @func - * @memberOf R - * @since v0.7.0 - * @category Function - * @sig (*... -> *) -> ([*]... -> [*]) - * @param {Function} fn The function to lift into higher context - * @return {Function} The lifted function. - * @see R.liftN - * @example - * - * var madd3 = R.lift((a, b, c) => a + b + c); - * - * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] - * - * var madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e); - * - * madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24] - */ -var lift = /*#__PURE__*/_curry1(function lift(fn) { - return liftN(fn.length, fn); -}); - -/** - * Returns a curried equivalent of the provided function. The curried function - * has two unusual capabilities. First, its arguments needn't be provided one - * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the - * following are equivalent: - * - * - `g(1)(2)(3)` - * - `g(1)(2, 3)` - * - `g(1, 2)(3)` - * - `g(1, 2, 3)` - * - * Secondly, the special placeholder value [`R.__`](#__) may be used to specify - * "gaps", allowing partial application of any combination of arguments, - * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), - * the following are equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (* -> a) -> (* -> a) - * @param {Function} fn The function to curry. - * @return {Function} A new, curried function. - * @see R.curryN - * @example - * - * var addFourNumbers = (a, b, c, d) => a + b + c + d; - * - * var curriedAddFourNumbers = R.curry(addFourNumbers); - * var f = curriedAddFourNumbers(1, 2); - * var g = f(3); - * g(4); //=> 10 - */ -var curry = /*#__PURE__*/_curry1(function curry(fn) { - return curryN(fn.length, fn); -}); - -/** - * Returns the result of calling its first argument with the remaining - * arguments. This is occasionally useful as a converging function for - * [`R.converge`](#converge): the first branch can produce a function while the - * remaining branches produce values to be passed to that function as its - * arguments. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig (*... -> a),*... -> a - * @param {Function} fn The function to apply to the remaining arguments. - * @param {...*} args Any number of positional arguments. - * @return {*} - * @see R.apply - * @example - * - * R.call(R.add, 1, 2); //=> 3 - * - * var indentN = R.pipe(R.repeat(' '), - * R.join(''), - * R.replace(/^(?!$)/gm)); - * - * var format = R.converge(R.call, [ - * R.pipe(R.prop('indent'), indentN), - * R.prop('value') - * ]); - * - * format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> ' foo\n bar\n baz\n' - * @symb R.call(f, a, b) = f(a, b) - */ -var call = /*#__PURE__*/curry(function call(fn) { - return fn.apply(this, Array.prototype.slice.call(arguments, 1)); -}); - -/** - * `_makeFlat` is a helper function that returns a one-level or fully recursive - * function based on the flag passed in. - * - * @private - */ -function _makeFlat(recursive) { - return function flatt(list) { - var value, jlen, j; - var result = []; - var idx = 0; - var ilen = list.length; - - while (idx < ilen) { - if (_isArrayLike(list[idx])) { - value = recursive ? flatt(list[idx]) : list[idx]; - j = 0; - jlen = value.length; - while (j < jlen) { - result[result.length] = value[j]; - j += 1; - } - } else { - result[result.length] = list[idx]; - } - idx += 1; - } - return result; - }; -} - -function _forceReduced(x) { - return { - '@@transducer/value': x, - '@@transducer/reduced': true - }; -} - -var preservingReduced = function (xf) { - return { - '@@transducer/init': _xfBase.init, - '@@transducer/result': function (result) { - return xf['@@transducer/result'](result); - }, - '@@transducer/step': function (result, input) { - var ret = xf['@@transducer/step'](result, input); - return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret; - } - }; -}; - -var _flatCat = function _xcat(xf) { - var rxf = preservingReduced(xf); - return { - '@@transducer/init': _xfBase.init, - '@@transducer/result': function (result) { - return rxf['@@transducer/result'](result); - }, - '@@transducer/step': function (result, input) { - return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input); - } - }; -}; - -var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) { - return map(f, _flatCat(xf)); -}); - -/** - * `chain` maps a function over a list and concatenates the results. `chain` - * is also known as `flatMap` in some libraries - * - * Dispatches to the `chain` method of the second argument, if present, - * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain). - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig Chain m => (a -> m b) -> m a -> m b - * @param {Function} fn The function to map with - * @param {Array} list The list to map over - * @return {Array} The result of flat-mapping `list` with `fn` - * @example - * - * var duplicate = n => [n, n]; - * R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3] - * - * R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1] - */ -var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { - if (typeof monad === 'function') { - return function (x) { - return fn(monad(x))(x); - }; - } - return _makeFlat(false)(map(fn, monad)); -})); - -function _cloneRegExp(pattern) { - return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : '')); -} - -/** - * Gives a single-word string description of the (native) type of a value, - * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not - * attempt to distinguish user Object types any further, reporting them all as - * 'Object'. - * - * @func - * @memberOf R - * @since v0.8.0 - * @category Type - * @sig (* -> {*}) -> String - * @param {*} val The value to test - * @return {String} - * @example - * - * R.type({}); //=> "Object" - * R.type(1); //=> "Number" - * R.type(false); //=> "Boolean" - * R.type('s'); //=> "String" - * R.type(null); //=> "Null" - * R.type([]); //=> "Array" - * R.type(/[A-z]/); //=> "RegExp" - * R.type(() => {}); //=> "Function" - * R.type(undefined); //=> "Undefined" - */ -var type = /*#__PURE__*/_curry1(function type(val) { - return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1); -}); - -/** - * Copies an object. - * - * @private - * @param {*} value The value to be copied - * @param {Array} refFrom Array containing the source references - * @param {Array} refTo Array containing the copied source references - * @param {Boolean} deep Whether or not to perform deep cloning. - * @return {*} The copied value. - */ -function _clone(value, refFrom, refTo, deep) { - var copy = function copy(copiedValue) { - var len = refFrom.length; - var idx = 0; - while (idx < len) { - if (value === refFrom[idx]) { - return refTo[idx]; - } - idx += 1; - } - refFrom[idx + 1] = value; - refTo[idx + 1] = copiedValue; - for (var key in value) { - copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key]; - } - return copiedValue; - }; - switch (type(value)) { - case 'Object': - return copy({}); - case 'Array': - return copy([]); - case 'Date': - return new Date(value.valueOf()); - case 'RegExp': - return _cloneRegExp(value); - default: - return value; - } -} - -/** - * Creates a deep copy of the value which may contain (nested) `Array`s and - * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are - * assigned by reference rather than copied - * - * Dispatches to a `clone` method if present. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {*} -> {*} - * @param {*} value The object or array to clone - * @return {*} A deeply cloned copy of `val` - * @example - * - * var objects = [{}, {}, {}]; - * var objectsClone = R.clone(objects); - * objects === objectsClone; //=> false - * objects[0] === objectsClone[0]; //=> false - */ -var clone = /*#__PURE__*/_curry1(function clone(value) { - return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true); -}); - -/** - * A function that returns the `!` of its argument. It will return `true` when - * passed false-y value, and `false` when passed a truth-y one. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Logic - * @sig * -> Boolean - * @param {*} a any value - * @return {Boolean} the logical inverse of passed argument. - * @see R.complement - * @example - * - * R.not(true); //=> false - * R.not(false); //=> true - * R.not(0); //=> true - * R.not(1); //=> false - */ -var not = /*#__PURE__*/_curry1(function not(a) { - return !a; -}); - -/** - * Takes a function `f` and returns a function `g` such that if called with the same arguments - * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`. - * - * `R.complement` may be applied to any functor - * - * @func - * @memberOf R - * @since v0.12.0 - * @category Logic - * @sig (*... -> *) -> (*... -> Boolean) - * @param {Function} f - * @return {Function} - * @see R.not - * @example - * - * var isNotNil = R.complement(R.isNil); - * isNil(null); //=> true - * isNotNil(null); //=> false - * isNil(7); //=> false - * isNotNil(7); //=> true - */ -var complement = /*#__PURE__*/lift(not); - -function _pipe(f, g) { - return function () { - return g.call(this, f.apply(this, arguments)); - }; -} - -/** - * This checks whether a function has a [methodname] function. If it isn't an - * array it will execute that function otherwise it will default to the ramda - * implementation. - * - * @private - * @param {Function} fn ramda implemtation - * @param {String} methodname property to check for a custom implementation - * @return {Object} Whatever the return value of the method is. - */ -function _checkForMethod(methodname, fn) { - return function () { - var length = arguments.length; - if (length === 0) { - return fn(); - } - var obj = arguments[length - 1]; - return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1)); - }; -} - -/** - * Returns the elements of the given list or string (or object with a `slice` - * method) from `fromIndex` (inclusive) to `toIndex` (exclusive). - * - * Dispatches to the `slice` method of the third argument, if present. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig Number -> Number -> [a] -> [a] - * @sig Number -> Number -> String -> String - * @param {Number} fromIndex The start index (inclusive). - * @param {Number} toIndex The end index (exclusive). - * @param {*} list - * @return {*} - * @example - * - * R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] - * R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd'] - * R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c'] - * R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] - * R.slice(0, 3, 'ramda'); //=> 'ram' - */ -var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) { - return Array.prototype.slice.call(list, fromIndex, toIndex); -})); - -/** - * Returns all but the first element of the given list or string (or object - * with a `tail` method). - * - * Dispatches to the `slice` method of the first argument, if present. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.head, R.init, R.last - * @example - * - * R.tail([1, 2, 3]); //=> [2, 3] - * R.tail([1, 2]); //=> [2] - * R.tail([1]); //=> [] - * R.tail([]); //=> [] - * - * R.tail('abc'); //=> 'bc' - * R.tail('ab'); //=> 'b' - * R.tail('a'); //=> '' - * R.tail(''); //=> '' - */ -var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity))); - -/** - * Performs left-to-right function composition. The leftmost function may have - * any arity; the remaining functions must be unary. - * - * In some libraries this function is named `sequence`. - * - * **Note:** The result of pipe is not automatically curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z) - * @param {...Function} functions - * @return {Function} - * @see R.compose - * @example - * - * var f = R.pipe(Math.pow, R.negate, R.inc); - * - * f(3, 4); // -(3^4) + 1 - * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b))) - */ -function pipe() { - if (arguments.length === 0) { - throw new Error('pipe requires at least one argument'); - } - return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments))); -} - -/** - * Returns a new list or string with the elements or characters in reverse - * order. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {Array|String} list - * @return {Array|String} - * @example - * - * R.reverse([1, 2, 3]); //=> [3, 2, 1] - * R.reverse([1, 2]); //=> [2, 1] - * R.reverse([1]); //=> [1] - * R.reverse([]); //=> [] - * - * R.reverse('abc'); //=> 'cba' - * R.reverse('ab'); //=> 'ba' - * R.reverse('a'); //=> 'a' - * R.reverse(''); //=> '' - */ -var reverse = /*#__PURE__*/_curry1(function reverse(list) { - return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse(); -}); - -/** - * Performs right-to-left function composition. The rightmost function may have - * any arity; the remaining functions must be unary. - * - * **Note:** The result of compose is not automatically curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z) - * @param {...Function} ...functions The functions to compose - * @return {Function} - * @see R.pipe - * @example - * - * var classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName - * var yellGreeting = R.compose(R.toUpper, classyGreeting); - * yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND" - * - * R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7 - * - * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b))) - */ -function compose() { - if (arguments.length === 0) { - throw new Error('compose requires at least one argument'); - } - return pipe.apply(this, reverse(arguments)); -} - -function _arrayFromIterator(iter) { - var list = []; - var next; - while (!(next = iter.next()).done) { - list.push(next.value); - } - return list; -} - -function _containsWith(pred, x, list) { - var idx = 0; - var len = list.length; - - while (idx < len) { - if (pred(x, list[idx])) { - return true; - } - idx += 1; - } - return false; -} - -function _functionName(f) { - // String(x => x) evaluates to "x => x", so the pattern may not match. - var match = String(f).match(/^function (\w*)/); - return match == null ? '' : match[1]; -} - -/** - * Returns true if its arguments are identical, false otherwise. Values are - * identical if they reference the same memory. `NaN` is identical to `NaN`; - * `0` and `-0` are not identical. - * - * @func - * @memberOf R - * @since v0.15.0 - * @category Relation - * @sig a -> a -> Boolean - * @param {*} a - * @param {*} b - * @return {Boolean} - * @example - * - * var o = {}; - * R.identical(o, o); //=> true - * R.identical(1, 1); //=> true - * R.identical(1, '1'); //=> false - * R.identical([], []); //=> false - * R.identical(0, -0); //=> false - * R.identical(NaN, NaN); //=> true - */ -var identical = /*#__PURE__*/_curry2(function identical(a, b) { - // SameValue algorithm - if (a === b) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - return a !== 0 || 1 / a === 1 / b; - } else { - // Step 6.a: NaN == NaN - return a !== a && b !== b; - } -}); - -/** - * private _uniqContentEquals function. - * That function is checking equality of 2 iterator contents with 2 assumptions - * - iterators lengths are the same - * - iterators values are unique - * - * false-positive result will be returned for comparision of, e.g. - * - [1,2,3] and [1,2,3,4] - * - [1,1,1] and [1,2,3] - * */ - -function _uniqContentEquals(aIterator, bIterator, stackA, stackB) { - var a = _arrayFromIterator(aIterator); - var b = _arrayFromIterator(bIterator); - - function eq(_a, _b) { - return _equals(_a, _b, stackA.slice(), stackB.slice()); - } - - // if *a* array contains any element that is not included in *b* - return !_containsWith(function (b, aItem) { - return !_containsWith(eq, aItem, b); - }, b, a); -} - -function _equals(a, b, stackA, stackB) { - if (identical(a, b)) { - return true; - } - - var typeA = type(a); - - if (typeA !== type(b)) { - return false; - } - - if (a == null || b == null) { - return false; - } - - if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') { - return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a); - } - - if (typeof a.equals === 'function' || typeof b.equals === 'function') { - return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a); - } - - switch (typeA) { - case 'Arguments': - case 'Array': - case 'Object': - if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') { - return a === b; - } - break; - case 'Boolean': - case 'Number': - case 'String': - if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf()))) { - return false; - } - break; - case 'Date': - if (!identical(a.valueOf(), b.valueOf())) { - return false; - } - break; - case 'Error': - return a.name === b.name && a.message === b.message; - case 'RegExp': - if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) { - return false; - } - break; - } - - var idx = stackA.length - 1; - while (idx >= 0) { - if (stackA[idx] === a) { - return stackB[idx] === b; - } - idx -= 1; - } - - switch (typeA) { - case 'Map': - if (a.size !== b.size) { - return false; - } - - return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b])); - case 'Set': - if (a.size !== b.size) { - return false; - } - - return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b])); - case 'Arguments': - case 'Array': - case 'Object': - case 'Boolean': - case 'Number': - case 'String': - case 'Date': - case 'Error': - case 'RegExp': - case 'Int8Array': - case 'Uint8Array': - case 'Uint8ClampedArray': - case 'Int16Array': - case 'Uint16Array': - case 'Int32Array': - case 'Uint32Array': - case 'Float32Array': - case 'Float64Array': - case 'ArrayBuffer': - break; - default: - // Values of other types are only equal if identical. - return false; - } - - var keysA = keys(a); - if (keysA.length !== keys(b).length) { - return false; - } - - var extendedStackA = stackA.concat([a]); - var extendedStackB = stackB.concat([b]); - - idx = keysA.length - 1; - while (idx >= 0) { - var key = keysA[idx]; - if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) { - return false; - } - idx -= 1; - } - return true; -} - -/** - * Returns `true` if its arguments are equivalent, `false` otherwise. Handles - * cyclical data structures. - * - * Dispatches symmetrically to the `equals` methods of both arguments, if - * present. - * - * @func - * @memberOf R - * @since v0.15.0 - * @category Relation - * @sig a -> b -> Boolean - * @param {*} a - * @param {*} b - * @return {Boolean} - * @example - * - * R.equals(1, 1); //=> true - * R.equals(1, '1'); //=> false - * R.equals([1, 2, 3], [1, 2, 3]); //=> true - * - * var a = {}; a.v = a; - * var b = {}; b.v = b; - * R.equals(a, b); //=> true - */ -var equals = /*#__PURE__*/_curry2(function equals(a, b) { - return _equals(a, b, [], []); -}); - -function _indexOf(list, a, idx) { - var inf, item; - // Array.prototype.indexOf doesn't exist below IE9 - if (typeof list.indexOf === 'function') { - switch (typeof a) { - case 'number': - if (a === 0) { - // manually crawl the list to distinguish between +0 and -0 - inf = 1 / a; - while (idx < list.length) { - item = list[idx]; - if (item === 0 && 1 / item === inf) { - return idx; - } - idx += 1; - } - return -1; - } else if (a !== a) { - // NaN - while (idx < list.length) { - item = list[idx]; - if (typeof item === 'number' && item !== item) { - return idx; - } - idx += 1; - } - return -1; - } - // non-zero numbers can utilise Set - return list.indexOf(a, idx); - - // all these types can utilise Set - case 'string': - case 'boolean': - case 'function': - case 'undefined': - return list.indexOf(a, idx); - - case 'object': - if (a === null) { - // null can utilise Set - return list.indexOf(a, idx); - } - } - } - // anything else not covered above, defer to R.equals - while (idx < list.length) { - if (equals(list[idx], a)) { - return idx; - } - idx += 1; - } - return -1; -} - -function _contains(a, list) { - return _indexOf(list, a, 0) >= 0; -} - -function _quote(s) { - var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace - .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0'); - - return '"' + escaped.replace(/"/g, '\\"') + '"'; -} - -/** - * Polyfill from . - */ -var pad = function pad(n) { - return (n < 10 ? '0' : '') + n; -}; - -var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) { - return d.toISOString(); -} : function _toISOString(d) { - return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'; -}; - -function _complement(f) { - return function () { - return !f.apply(this, arguments); - }; -} - -function _filter(fn, list) { - var idx = 0; - var len = list.length; - var result = []; - - while (idx < len) { - if (fn(list[idx])) { - result[result.length] = list[idx]; - } - idx += 1; - } - return result; -} - -function _isObject(x) { - return Object.prototype.toString.call(x) === '[object Object]'; -} - -var XFilter = /*#__PURE__*/function () { - function XFilter(f, xf) { - this.xf = xf; - this.f = f; - } - XFilter.prototype['@@transducer/init'] = _xfBase.init; - XFilter.prototype['@@transducer/result'] = _xfBase.result; - XFilter.prototype['@@transducer/step'] = function (result, input) { - return this.f(input) ? this.xf['@@transducer/step'](result, input) : result; - }; - - return XFilter; -}(); - -var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) { - return new XFilter(f, xf); -}); - -/** - * Takes a predicate and a `Filterable`, and returns a new filterable of the - * same type containing the members of the given filterable which satisfy the - * given predicate. Filterable objects include plain objects or any object - * that has a filter method such as `Array`. - * - * Dispatches to the `filter` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> f a - * @param {Function} pred - * @param {Array} filterable - * @return {Array} Filterable - * @see R.reject, R.transduce, R.addIndex - * @example - * - * var isEven = n => n % 2 === 0; - * - * R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4] - * - * R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} - */ -var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) { - return _isObject(filterable) ? _reduce(function (acc, key) { - if (pred(filterable[key])) { - acc[key] = filterable[key]; - } - return acc; - }, {}, keys(filterable)) : - // else - _filter(pred, filterable); -})); - -/** - * The complement of [`filter`](#filter). - * - * Acts as a transducer if a transformer is given in list position. Filterable - * objects include plain objects or any object that has a filter method such - * as `Array`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> f a - * @param {Function} pred - * @param {Array} filterable - * @return {Array} - * @see R.filter, R.transduce, R.addIndex - * @example - * - * var isOdd = (n) => n % 2 === 1; - * - * R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4] - * - * R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} - */ -var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) { - return filter(_complement(pred), filterable); -}); - -function _toString(x, seen) { - var recur = function recur(y) { - var xs = seen.concat([x]); - return _contains(y, xs) ? '' : _toString(y, xs); - }; - - // mapPairs :: (Object, [String]) -> [String] - var mapPairs = function (obj, keys$$1) { - return _map(function (k) { - return _quote(k) + ': ' + recur(obj[k]); - }, keys$$1.slice().sort()); - }; - - switch (Object.prototype.toString.call(x)) { - case '[object Arguments]': - return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))'; - case '[object Array]': - return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) { - return (/^\d+$/.test(k) - ); - }, keys(x)))).join(', ') + ']'; - case '[object Boolean]': - return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString(); - case '[object Date]': - return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')'; - case '[object Null]': - return 'null'; - case '[object Number]': - return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10); - case '[object String]': - return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x); - case '[object Undefined]': - return 'undefined'; - default: - if (typeof x.toString === 'function') { - var repr = x.toString(); - if (repr !== '[object Object]') { - return repr; - } - } - return '{' + mapPairs(x, keys(x)).join(', ') + '}'; - } -} - -/** - * Returns the string representation of the given value. `eval`'ing the output - * should result in a value equivalent to the input value. Many of the built-in - * `toString` methods do not satisfy this requirement. - * - * If the given value is an `[object Object]` with a `toString` method other - * than `Object.prototype.toString`, this method is invoked with no arguments - * to produce the return value. This means user-defined constructor functions - * can provide a suitable `toString` method. For example: - * - * function Point(x, y) { - * this.x = x; - * this.y = y; - * } - * - * Point.prototype.toString = function() { - * return 'new Point(' + this.x + ', ' + this.y + ')'; - * }; - * - * R.toString(new Point(1, 2)); //=> 'new Point(1, 2)' - * - * @func - * @memberOf R - * @since v0.14.0 - * @category String - * @sig * -> String - * @param {*} val - * @return {String} - * @example - * - * R.toString(42); //=> '42' - * R.toString('abc'); //=> '"abc"' - * R.toString([1, 2, 3]); //=> '[1, 2, 3]' - * R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}' - * R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")' - */ -var toString$1 = /*#__PURE__*/_curry1(function toString(val) { - return _toString(val, []); -}); - -/** - * Returns the result of concatenating the given lists or strings. - * - * Note: `R.concat` expects both arguments to be of the same type, - * unlike the native `Array.prototype.concat` method. It will throw - * an error if you `concat` an Array with a non-Array value. - * - * Dispatches to the `concat` method of the first argument, if present. - * Can also concatenate two members of a [fantasy-land - * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup). - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] -> [a] - * @sig String -> String -> String - * @param {Array|String} firstList The first list - * @param {Array|String} secondList The second list - * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of - * `secondList`. - * - * @example - * - * R.concat('ABC', 'DEF'); // 'ABCDEF' - * R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] - * R.concat([], []); //=> [] - */ -var concat = /*#__PURE__*/_curry2(function concat(a, b) { - if (_isArray(a)) { - if (_isArray(b)) { - return a.concat(b); - } - throw new TypeError(toString$1(b) + ' is not an array'); - } - if (_isString(a)) { - if (_isString(b)) { - return a + b; - } - throw new TypeError(toString$1(b) + ' is not a string'); - } - if (a != null && _isFunction(a['fantasy-land/concat'])) { - return a['fantasy-land/concat'](b); - } - if (a != null && _isFunction(a.concat)) { - return a.concat(b); - } - throw new TypeError(toString$1(a) + ' does not have a method named "concat" or "fantasy-land/concat"'); -}); - -/** - * Returns `true` if the specified value is equal, in [`R.equals`](#equals) - * terms, to at least one element of the given list; `false` otherwise. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig a -> [a] -> Boolean - * @param {Object} a The item to compare against. - * @param {Array} list The array to consider. - * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise. - * @see R.any - * @example - * - * R.contains(3, [1, 2, 3]); //=> true - * R.contains(4, [1, 2, 3]); //=> false - * R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true - * R.contains([42], [[42]]); //=> true - */ -var contains$1 = /*#__PURE__*/_curry2(_contains); - -/** - * Accepts a converging function and a list of branching functions and returns - * a new function. When invoked, this new function is applied to some - * arguments, each branching function is applied to those same arguments. The - * results of each branching function are passed as arguments to the converging - * function to produce the return value. - * - * @func - * @memberOf R - * @since v0.4.2 - * @category Function - * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z) - * @param {Function} after A function. `after` will be invoked with the return values of - * `fn1` and `fn2` as its arguments. - * @param {Array} functions A list of functions. - * @return {Function} A new function. - * @see R.useWith - * @example - * - * var average = R.converge(R.divide, [R.sum, R.length]) - * average([1, 2, 3, 4, 5, 6, 7]) //=> 4 - * - * var strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower]) - * strangeConcat("Yodel") //=> "YODELyodel" - * - * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b)) - */ -var converge = /*#__PURE__*/_curry2(function converge(after, fns) { - return curryN(reduce(max, 0, pluck('length', fns)), function () { - var args = arguments; - var context = this; - return after.apply(context, _map(function (fn) { - return fn.apply(context, args); - }, fns)); - }); -}); - -var XReduceBy = /*#__PURE__*/function () { - function XReduceBy(valueFn, valueAcc, keyFn, xf) { - this.valueFn = valueFn; - this.valueAcc = valueAcc; - this.keyFn = keyFn; - this.xf = xf; - this.inputs = {}; - } - XReduceBy.prototype['@@transducer/init'] = _xfBase.init; - XReduceBy.prototype['@@transducer/result'] = function (result) { - var key; - for (key in this.inputs) { - if (_has(key, this.inputs)) { - result = this.xf['@@transducer/step'](result, this.inputs[key]); - if (result['@@transducer/reduced']) { - result = result['@@transducer/value']; - break; - } - } - } - this.inputs = null; - return this.xf['@@transducer/result'](result); - }; - XReduceBy.prototype['@@transducer/step'] = function (result, input) { - var key = this.keyFn(input); - this.inputs[key] = this.inputs[key] || [key, this.valueAcc]; - this.inputs[key][1] = this.valueFn(this.inputs[key][1], input); - return result; - }; - - return XReduceBy; -}(); - -var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) { - return new XReduceBy(valueFn, valueAcc, keyFn, xf); -}); - -/** - * Groups the elements of the list according to the result of calling - * the String-returning function `keyFn` on each element and reduces the elements - * of each group to a single value via the reducer function `valueFn`. - * - * This function is basically a more general [`groupBy`](#groupBy) function. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.20.0 - * @category List - * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a} - * @param {Function} valueFn The function that reduces the elements of each group to a single - * value. Receives two values, accumulator for a particular group and the current element. - * @param {*} acc The (initial) accumulator value for each group. - * @param {Function} keyFn The function that maps the list's element into a key. - * @param {Array} list The array to group. - * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of - * `valueFn` for elements which produced that key when passed to `keyFn`. - * @see R.groupBy, R.reduce - * @example - * - * var reduceToNamesBy = R.reduceBy((acc, student) => acc.concat(student.name), []); - * var namesByGrade = reduceToNamesBy(function(student) { - * var score = student.score; - * return score < 65 ? 'F' : - * score < 70 ? 'D' : - * score < 80 ? 'C' : - * score < 90 ? 'B' : 'A'; - * }); - * var students = [{name: 'Lucy', score: 92}, - * {name: 'Drew', score: 85}, - * // ... - * {name: 'Bart', score: 62}]; - * namesByGrade(students); - * // { - * // 'A': ['Lucy'], - * // 'B': ['Drew'] - * // // ..., - * // 'F': ['Bart'] - * // } - */ -var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) { - return _reduce(function (acc, elt) { - var key = keyFn(elt); - acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt); - return acc; - }, {}, list); -})); - -/** - * Counts the elements of a list according to how many match each value of a - * key generated by the supplied function. Returns an object mapping the keys - * produced by `fn` to the number of occurrences in the list. Note that all - * keys are coerced to strings because of how JavaScript objects work. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig (a -> String) -> [a] -> {*} - * @param {Function} fn The function used to map values to keys. - * @param {Array} list The list to count elements from. - * @return {Object} An object mapping keys to number of occurrences in the list. - * @example - * - * var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2]; - * R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1} - * - * var letters = ['a', 'b', 'A', 'a', 'B', 'c']; - * R.countBy(R.toLower)(letters); //=> {'a': 3, 'b': 2, 'c': 1} - */ -var countBy = /*#__PURE__*/reduceBy(function (acc, elem) { - return acc + 1; -}, 0); - -/** - * Decrements its argument. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Math - * @sig Number -> Number - * @param {Number} n - * @return {Number} n - 1 - * @see R.inc - * @example - * - * R.dec(42); //=> 41 - */ -var dec = /*#__PURE__*/add(-1); - -/** - * Finds the set (i.e. no duplicates) of all elements in the first list not - * contained in the second list. Objects and Arrays are compared in terms of - * value equality, not reference equality. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig [*] -> [*] -> [*] - * @param {Array} list1 The first list. - * @param {Array} list2 The second list. - * @return {Array} The elements in `list1` that are not in `list2`. - * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without - * @example - * - * R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2] - * R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5] - * R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}] - */ -var difference = /*#__PURE__*/_curry2(function difference(first, second) { - var out = []; - var idx = 0; - var firstLen = first.length; - while (idx < firstLen) { - if (!_contains(first[idx], second) && !_contains(first[idx], out)) { - out[out.length] = first[idx]; - } - idx += 1; - } - return out; -}); - -var XDropRepeatsWith = /*#__PURE__*/function () { - function XDropRepeatsWith(pred, xf) { - this.xf = xf; - this.pred = pred; - this.lastValue = undefined; - this.seenFirstValue = false; - } - - XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init; - XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result; - XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) { - var sameAsLast = false; - if (!this.seenFirstValue) { - this.seenFirstValue = true; - } else if (this.pred(this.lastValue, input)) { - sameAsLast = true; - } - this.lastValue = input; - return sameAsLast ? result : this.xf['@@transducer/step'](result, input); - }; - - return XDropRepeatsWith; -}(); - -var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) { - return new XDropRepeatsWith(pred, xf); -}); - -/** - * Returns the nth element of the given list or string. If n is negative the - * element at index length + n is returned. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Number -> [a] -> a | Undefined - * @sig Number -> String -> String - * @param {Number} offset - * @param {*} list - * @return {*} - * @example - * - * var list = ['foo', 'bar', 'baz', 'quux']; - * R.nth(1, list); //=> 'bar' - * R.nth(-1, list); //=> 'quux' - * R.nth(-99, list); //=> undefined - * - * R.nth(2, 'abc'); //=> 'c' - * R.nth(3, 'abc'); //=> '' - * @symb R.nth(-1, [a, b, c]) = c - * @symb R.nth(0, [a, b, c]) = a - * @symb R.nth(1, [a, b, c]) = b - */ -var nth = /*#__PURE__*/_curry2(function nth(offset, list) { - var idx = offset < 0 ? list.length + offset : offset; - return _isString(list) ? list.charAt(idx) : list[idx]; -}); - -/** - * Returns the last element of the given list or string. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig [a] -> a | Undefined - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.init, R.head, R.tail - * @example - * - * R.last(['fi', 'fo', 'fum']); //=> 'fum' - * R.last([]); //=> undefined - * - * R.last('abc'); //=> 'c' - * R.last(''); //=> '' - */ -var last = /*#__PURE__*/nth(-1); - -/** - * Returns a new list without any consecutively repeating elements. Equality is - * determined by applying the supplied predicate to each pair of consecutive elements. The - * first element in a series of equal elements will be preserved. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.14.0 - * @category List - * @sig ((a, a) -> Boolean) -> [a] -> [a] - * @param {Function} pred A predicate used to test whether two items are equal. - * @param {Array} list The array to consider. - * @return {Array} `list` without repeating elements. - * @see R.transduce - * @example - * - * var l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3]; - * R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3] - */ -var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) { - var result = []; - var idx = 1; - var len = list.length; - if (len !== 0) { - result[0] = list[0]; - while (idx < len) { - if (!pred(last(result), list[idx])) { - result[result.length] = list[idx]; - } - idx += 1; - } - } - return result; -})); - -/** - * Returns a new list without any consecutively repeating elements. - * [`R.equals`](#equals) is used to determine equality. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.14.0 - * @category List - * @sig [a] -> [a] - * @param {Array} list The array to consider. - * @return {Array} `list` without repeating elements. - * @see R.transduce - * @example - * - * R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2] - */ -var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals))); - -/** - * Returns the empty value of its argument's type. Ramda defines the empty - * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other - * types are supported if they define `.empty`, - * `.prototype.empty` or implement the - * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid). - * - * Dispatches to the `empty` method of the first argument, if present. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category Function - * @sig a -> a - * @param {*} x - * @return {*} - * @example - * - * R.empty(Just(42)); //=> Nothing() - * R.empty([1, 2, 3]); //=> [] - * R.empty('unicorns'); //=> '' - * R.empty({x: 1, y: 2}); //=> {} - */ -var empty = /*#__PURE__*/_curry1(function empty(x) { - return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () { - return arguments; - }() : - // else - void 0; -}); - -/** - * Returns a new function much like the supplied one, except that the first two - * arguments' order is reversed. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z) - * @param {Function} fn The function to invoke with its first two parameters reversed. - * @return {*} The result of invoking `fn` with its first two parameters' order reversed. - * @example - * - * var mergeThree = (a, b, c) => [].concat(a, b, c); - * - * mergeThree(1, 2, 3); //=> [1, 2, 3] - * - * R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3] - * @symb R.flip(f)(a, b, c) = f(b, a, c) - */ -var flip = /*#__PURE__*/_curry1(function flip(fn) { - return curryN(fn.length, function (a, b) { - var args = Array.prototype.slice.call(arguments, 0); - args[0] = b; - args[1] = a; - return fn.apply(this, args); - }); -}); - -/** - * Iterate over an input `list`, calling a provided function `fn` for each - * element in the list. - * - * `fn` receives one argument: *(value)*. - * - * Note: `R.forEach` does not skip deleted or unassigned indices (sparse - * arrays), unlike the native `Array.prototype.forEach` method. For more - * details on this behavior, see: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description - * - * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns - * the original array. In some libraries this function is named `each`. - * - * Dispatches to the `forEach` method of the second argument, if present. - * - * @func - * @memberOf R - * @since v0.1.1 - * @category List - * @sig (a -> *) -> [a] -> [a] - * @param {Function} fn The function to invoke. Receives one argument, `value`. - * @param {Array} list The list to iterate over. - * @return {Array} The original list. - * @see R.addIndex - * @example - * - * var printXPlusFive = x => console.log(x + 5); - * R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3] - * // logs 6 - * // logs 7 - * // logs 8 - * @symb R.forEach(f, [a, b, c]) = [a, b, c] - */ -var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) { - var len = list.length; - var idx = 0; - while (idx < len) { - fn(list[idx]); - idx += 1; - } - return list; -})); - -/** - * Iterate over an input `object`, calling a provided function `fn` for each - * key and value in the object. - * - * `fn` receives three argument: *(value, key, obj)*. - * - * @func - * @memberOf R - * @since v0.23.0 - * @category Object - * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a - * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`. - * @param {Object} obj The object to iterate over. - * @return {Object} The original object. - * @example - * - * var printKeyConcatValue = (value, key) => console.log(key + ':' + value); - * R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2} - * // logs x:1 - * // logs y:2 - * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b} - */ -var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) { - var keyList = keys(obj); - var idx = 0; - while (idx < keyList.length) { - var key = keyList[idx]; - fn(obj[key], key, obj); - idx += 1; - } - return obj; -}); - -/** - * Splits a list into sub-lists stored in an object, based on the result of - * calling a String-returning function on each element, and grouping the - * results according to values returned. - * - * Dispatches to the `groupBy` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig (a -> String) -> [a] -> {String: [a]} - * @param {Function} fn Function :: a -> String - * @param {Array} list The array to group - * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements - * that produced that key when passed to `fn`. - * @see R.transduce - * @example - * - * var byGrade = R.groupBy(function(student) { - * var score = student.score; - * return score < 65 ? 'F' : - * score < 70 ? 'D' : - * score < 80 ? 'C' : - * score < 90 ? 'B' : 'A'; - * }); - * var students = [{name: 'Abby', score: 84}, - * {name: 'Eddy', score: 58}, - * // ... - * {name: 'Jack', score: 69}]; - * byGrade(students); - * // { - * // 'A': [{name: 'Dianne', score: 99}], - * // 'B': [{name: 'Abby', score: 84}] - * // // ..., - * // 'F': [{name: 'Eddy', score: 58}] - * // } - */ -var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) { - if (acc == null) { - acc = []; - } - acc.push(item); - return acc; -}, null))); - -/** - * Returns the first element of the given list or string. In some libraries - * this function is named `first`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> a | Undefined - * @sig String -> String - * @param {Array|String} list - * @return {*} - * @see R.tail, R.init, R.last - * @example - * - * R.head(['fi', 'fo', 'fum']); //=> 'fi' - * R.head([]); //=> undefined - * - * R.head('abc'); //=> 'a' - * R.head(''); //=> '' - */ -var head = /*#__PURE__*/nth(0); - -function _identity(x) { - return x; -} - -/** - * A function that does nothing but return the parameter supplied to it. Good - * as a default or placeholder function. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig a -> a - * @param {*} x The value to return. - * @return {*} The input value, `x`. - * @example - * - * R.identity(1); //=> 1 - * - * var obj = {}; - * R.identity(obj) === obj; //=> true - * @symb R.identity(a) = a - */ -var identity = /*#__PURE__*/_curry1(_identity); - -/** - * Increments its argument. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Math - * @sig Number -> Number - * @param {Number} n - * @return {Number} n + 1 - * @see R.dec - * @example - * - * R.inc(42); //=> 43 - */ -var inc = /*#__PURE__*/add(1); - -/** - * Given a function that generates a key, turns a list of objects into an - * object indexing the objects by the given key. Note that if multiple - * objects generate the same value for the indexing key only the last value - * will be included in the generated object. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category List - * @sig (a -> String) -> [{k: v}] -> {k: {k: v}} - * @param {Function} fn Function :: a -> String - * @param {Array} array The array of objects to index - * @return {Object} An object indexing each array element by the given property. - * @example - * - * var list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}]; - * R.indexBy(R.prop('id'), list); - * //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}} - */ -var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) { - return elem; -}, null); - -/** - * Returns all but the last element of the given list or string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.last, R.head, R.tail - * @example - * - * R.init([1, 2, 3]); //=> [1, 2] - * R.init([1, 2]); //=> [1] - * R.init([1]); //=> [] - * R.init([]); //=> [] - * - * R.init('abc'); //=> 'ab' - * R.init('ab'); //=> 'a' - * R.init('a'); //=> '' - * R.init(''); //=> '' - */ -var init = /*#__PURE__*/slice(0, -1); - -var _Set = /*#__PURE__*/function () { - function _Set() { - /* globals Set */ - this._nativeSet = typeof Set === 'function' ? new Set() : null; - this._items = {}; - } - - // until we figure out why jsdoc chokes on this - // @param item The item to add to the Set - // @returns {boolean} true if the item did not exist prior, otherwise false - // - _Set.prototype.add = function (item) { - return !hasOrAdd(item, true, this); - }; - - // - // @param item The item to check for existence in the Set - // @returns {boolean} true if the item exists in the Set, otherwise false - // - _Set.prototype.has = function (item) { - return hasOrAdd(item, false, this); - }; - - // - // Combines the logic for checking whether an item is a member of the set and - // for adding a new item to the set. - // - // @param item The item to check or add to the Set instance. - // @param shouldAdd If true, the item will be added to the set if it doesn't - // already exist. - // @param set The set instance to check or add to. - // @return {boolean} true if the item already existed, otherwise false. - // - return _Set; -}(); - -function hasOrAdd(item, shouldAdd, set) { - var type = typeof item; - var prevSize, newSize; - switch (type) { - case 'string': - case 'number': - // distinguish between +0 and -0 - if (item === 0 && 1 / item === -Infinity) { - if (set._items['-0']) { - return true; - } else { - if (shouldAdd) { - set._items['-0'] = true; - } - return false; - } - } - // these types can all utilise the native Set - if (set._nativeSet !== null) { - if (shouldAdd) { - prevSize = set._nativeSet.size; - set._nativeSet.add(item); - newSize = set._nativeSet.size; - return newSize === prevSize; - } else { - return set._nativeSet.has(item); - } - } else { - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = {}; - set._items[type][item] = true; - } - return false; - } else if (item in set._items[type]) { - return true; - } else { - if (shouldAdd) { - set._items[type][item] = true; - } - return false; - } - } - - case 'boolean': - // set._items['boolean'] holds a two element array - // representing [ falseExists, trueExists ] - if (type in set._items) { - var bIdx = item ? 1 : 0; - if (set._items[type][bIdx]) { - return true; - } else { - if (shouldAdd) { - set._items[type][bIdx] = true; - } - return false; - } - } else { - if (shouldAdd) { - set._items[type] = item ? [false, true] : [true, false]; - } - return false; - } - - case 'function': - // compare functions for reference equality - if (set._nativeSet !== null) { - if (shouldAdd) { - prevSize = set._nativeSet.size; - set._nativeSet.add(item); - newSize = set._nativeSet.size; - return newSize === prevSize; - } else { - return set._nativeSet.has(item); - } - } else { - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = [item]; - } - return false; - } - if (!_contains(item, set._items[type])) { - if (shouldAdd) { - set._items[type].push(item); - } - return false; - } - return true; - } - - case 'undefined': - if (set._items[type]) { - return true; - } else { - if (shouldAdd) { - set._items[type] = true; - } - return false; - } - - case 'object': - if (item === null) { - if (!set._items['null']) { - if (shouldAdd) { - set._items['null'] = true; - } - return false; - } - return true; - } - /* falls through */ - default: - // reduce the search size of heterogeneous sets by creating buckets - // for each type. - type = Object.prototype.toString.call(item); - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = [item]; - } - return false; - } - // scan through all previously applied items - if (!_contains(item, set._items[type])) { - if (shouldAdd) { - set._items[type].push(item); - } - return false; - } - return true; - } -} - -/** - * Returns a new list containing only one copy of each element in the original - * list, based upon the value returned by applying the supplied function to - * each list element. Prefers the first item if the supplied function produces - * the same value on two items. [`R.equals`](#equals) is used for comparison. - * - * @func - * @memberOf R - * @since v0.16.0 - * @category List - * @sig (a -> b) -> [a] -> [a] - * @param {Function} fn A function used to produce a value to use during comparisons. - * @param {Array} list The array to consider. - * @return {Array} The list of unique items. - * @example - * - * R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10] - */ -var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) { - var set = new _Set(); - var result = []; - var idx = 0; - var appliedItem, item; - - while (idx < list.length) { - item = list[idx]; - appliedItem = fn(item); - if (set.add(appliedItem)) { - result.push(item); - } - idx += 1; - } - return result; -}); - -/** - * Returns a new list containing only one copy of each element in the original - * list. [`R.equals`](#equals) is used to determine equality. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @param {Array} list The array to consider. - * @return {Array} The list of unique items. - * @example - * - * R.uniq([1, 1, 2, 1]); //=> [1, 2] - * R.uniq([1, '1']); //=> [1, '1'] - * R.uniq([[42], [42]]); //=> [[42]] - */ -var uniq = /*#__PURE__*/uniqBy(identity); - -/** - * Turns a named method with a specified arity into a function that can be - * called directly supplied with arguments and a target object. - * - * The returned function is curried and accepts `arity + 1` parameters where - * the final parameter is the target object. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *) - * @param {Number} arity Number of arguments the returned function should take - * before the target object. - * @param {String} method Name of the method to call. - * @return {Function} A new curried function. - * @see R.construct - * @example - * - * var sliceFrom = R.invoker(1, 'slice'); - * sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm' - * var sliceFrom6 = R.invoker(2, 'slice')(6); - * sliceFrom6(8, 'abcdefghijklm'); //=> 'gh' - * @symb R.invoker(0, 'method')(o) = o['method']() - * @symb R.invoker(1, 'method')(a, o) = o['method'](a) - * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b) - */ -var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) { - return curryN(arity + 1, function () { - var target = arguments[arity]; - if (target != null && _isFunction(target[method])) { - return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity)); - } - throw new TypeError(toString$1(target) + ' does not have a method named "' + method + '"'); - }); -}); - -/** - * Returns `true` if the given value is its type's empty value; `false` - * otherwise. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Logic - * @sig a -> Boolean - * @param {*} x - * @return {Boolean} - * @see R.empty - * @example - * - * R.isEmpty([1, 2, 3]); //=> false - * R.isEmpty([]); //=> true - * R.isEmpty(''); //=> true - * R.isEmpty(null); //=> false - * R.isEmpty({}); //=> true - * R.isEmpty({length: 0}); //=> false - */ -var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) { - return x != null && equals(x, empty(x)); -}); - -/** - * Returns a string made by inserting the `separator` between each element and - * concatenating all the elements into a single string. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig String -> [a] -> String - * @param {Number|String} separator The string used to separate the elements. - * @param {Array} xs The elements to join into a string. - * @return {String} str The string made by concatenating `xs` with `separator`. - * @see R.split - * @example - * - * var spacer = R.join(' '); - * spacer(['a', 2, 3.4]); //=> 'a 2 3.4' - * R.join('|', [1, 2, 3]); //=> '1|2|3' - */ -var join = /*#__PURE__*/invoker(1, 'join'); - -/** - * juxt applies a list of functions to a list of values. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Function - * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n]) - * @param {Array} fns An array of functions - * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters. - * @see R.applySpec - * @example - * - * var getRange = R.juxt([Math.min, Math.max]); - * getRange(3, 4, 9, -3); //=> [-3, 9] - * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)] - */ -var juxt = /*#__PURE__*/_curry1(function juxt(fns) { - return converge(function () { - return Array.prototype.slice.call(arguments, 0); - }, fns); -}); - -function _isNumber(x) { - return Object.prototype.toString.call(x) === '[object Number]'; -} - -/** - * Returns the number of elements in the array by returning `list.length`. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig [a] -> Number - * @param {Array} list The array to inspect. - * @return {Number} The length of the array. - * @example - * - * R.length([]); //=> 0 - * R.length([1, 2, 3]); //=> 3 - */ -var length = /*#__PURE__*/_curry1(function length(list) { - return list != null && _isNumber(list.length) ? list.length : NaN; -}); - -/** - * Adds together all the elements of a list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig [Number] -> Number - * @param {Array} list An array of numbers - * @return {Number} The sum of all the numbers in the list. - * @see R.reduce - * @example - * - * R.sum([2,4,6,8,100,1]); //=> 121 - */ -var sum = /*#__PURE__*/reduce(add, 0); - -/** - * A customisable version of [`R.memoize`](#memoize). `memoizeWith` takes an - * additional function that will be applied to a given argument set and used to - * create the cache key under which the results of the function to be memoized - * will be stored. Care must be taken when implementing key generation to avoid - * clashes that may overwrite previous entries erroneously. - * - * - * @func - * @memberOf R - * @since v0.24.0 - * @category Function - * @sig (*... -> String) -> (*... -> a) -> (*... -> a) - * @param {Function} fn The function to generate the cache key. - * @param {Function} fn The function to memoize. - * @return {Function} Memoized version of `fn`. - * @see R.memoize - * @example - * - * let count = 0; - * const factorial = R.memoizeWith(R.identity, n => { - * count += 1; - * return R.product(R.range(1, n + 1)); - * }); - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * count; //=> 1 - */ -var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) { - var cache = {}; - return _arity(fn.length, function () { - var key = mFn.apply(this, arguments); - if (!_has(key, cache)) { - cache[key] = fn.apply(this, arguments); - } - return cache[key]; - }); -}); - -/** - * Creates a new function that, when invoked, caches the result of calling `fn` - * for a given argument set and returns the result. Subsequent calls to the - * memoized `fn` with the same argument set will not result in an additional - * call to `fn`; instead, the cached result for that set of arguments will be - * returned. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (*... -> a) -> (*... -> a) - * @param {Function} fn The function to memoize. - * @return {Function} Memoized version of `fn`. - * @see R.memoizeWith - * @deprecated since v0.25.0 - * @example - * - * let count = 0; - * const factorial = R.memoize(n => { - * count += 1; - * return R.product(R.range(1, n + 1)); - * }); - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * count; //=> 1 - */ -var memoize = /*#__PURE__*/memoizeWith(function () { - return toString$1(arguments); -}); - -/** - * Creates a new object with the own properties of the two provided objects. If - * a key exists in both objects, the provided function is applied to the key - * and the values associated with the key in each object, with the result being - * used as the value associated with the key in the returned object. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Object - * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a} - * @param {Function} fn - * @param {Object} l - * @param {Object} r - * @return {Object} - * @see R.mergeDeepWithKey, R.merge, R.mergeWith - * @example - * - * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r - * R.mergeWithKey(concatValues, - * { a: true, thing: 'foo', values: [10, 20] }, - * { b: true, thing: 'bar', values: [15, 35] }); - * //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] } - * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 } - */ -var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) { - var result = {}; - var k; - - for (k in l) { - if (_has(k, l)) { - result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k]; - } - } - - for (k in r) { - if (_has(k, r) && !_has(k, result)) { - result[k] = r[k]; - } - } - - return result; -}); - -/** - * Creates a new object with the own properties of the two provided objects. If - * a key exists in both objects, the provided function is applied to the values - * associated with the key in each object, with the result being used as the - * value associated with the key in the returned object. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Object - * @sig ((a, a) -> a) -> {a} -> {a} -> {a} - * @param {Function} fn - * @param {Object} l - * @param {Object} r - * @return {Object} - * @see R.mergeDeepWith, R.merge, R.mergeWithKey - * @example - * - * R.mergeWith(R.concat, - * { a: true, values: [10, 20] }, - * { b: true, values: [15, 35] }); - * //=> { a: true, b: true, values: [10, 20, 15, 35] } - */ -var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) { - return mergeWithKey(function (_, _l, _r) { - return fn(_l, _r); - }, l, r); -}); - -/** - * Multiplies two numbers. Equivalent to `a * b` but curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig Number -> Number -> Number - * @param {Number} a The first value. - * @param {Number} b The second value. - * @return {Number} The result of `a * b`. - * @see R.divide - * @example - * - * var double = R.multiply(2); - * var triple = R.multiply(3); - * double(3); //=> 6 - * triple(4); //=> 12 - * R.multiply(2, 5); //=> 10 - */ -var multiply = /*#__PURE__*/_curry2(function multiply(a, b) { - return a * b; -}); - -function _createPartialApplicator(concat) { - return _curry2(function (fn, args) { - return _arity(Math.max(0, fn.length - args.length), function () { - return fn.apply(this, concat(args, arguments)); - }); - }); -} - -/** - * Takes a function `f` and a list of arguments, and returns a function `g`. - * When applied, `g` returns the result of applying `f` to the arguments - * provided to `g` followed by the arguments provided initially. - * - * @func - * @memberOf R - * @since v0.10.0 - * @category Function - * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x) - * @param {Function} f - * @param {Array} args - * @return {Function} - * @see R.partial - * @example - * - * var greet = (salutation, title, firstName, lastName) => - * salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; - * - * var greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']); - * - * greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!' - * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b) - */ -var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat)); - -/** - * Takes a predicate and a list or other `Filterable` object and returns the - * pair of filterable objects of the same type of elements which do and do not - * satisfy, the predicate, respectively. Filterable objects include plain objects or any object - * that has a filter method such as `Array`. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a] - * @param {Function} pred A predicate to determine which side the element belongs to. - * @param {Array} filterable the list (or other filterable) to partition. - * @return {Array} An array, containing first the subset of elements that satisfy the - * predicate, and second the subset of elements that do not satisfy. - * @see R.filter, R.reject - * @example - * - * R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); - * // => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] - * - * R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' }); - * // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ] - */ -var partition = /*#__PURE__*/juxt([filter, reject]); - -/** - * Similar to `pick` except that this one includes a `key: undefined` pair for - * properties that don't exist. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig [k] -> {k: v} -> {k: v} - * @param {Array} names an array of String property names to copy onto a new object - * @param {Object} obj The object to copy from - * @return {Object} A new object with only properties from `names` on it. - * @see R.pick - * @example - * - * R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} - * R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined} - */ -var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) { - var result = {}; - var idx = 0; - var len = names.length; - while (idx < len) { - var name = names[idx]; - result[name] = obj[name]; - idx += 1; - } - return result; -}); - -/** - * Multiplies together all the elements of a list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig [Number] -> Number - * @param {Array} list An array of numbers - * @return {Number} The product of all the numbers in the list. - * @see R.reduce - * @example - * - * R.product([2,4,6,8,100,1]); //=> 38400 - */ -var product = /*#__PURE__*/reduce(multiply, 1); - -/** - * Accepts a function `fn` and a list of transformer functions and returns a - * new curried function. When the new function is invoked, it calls the - * function `fn` with parameters consisting of the result of calling each - * supplied handler on successive arguments to the new function. - * - * If more arguments are passed to the returned function than transformer - * functions, those arguments are passed directly to `fn` as additional - * parameters. If you expect additional arguments that don't need to be - * transformed, although you can ignore them, it's best to pass an identity - * function so that the new function reports the correct arity. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z) - * @param {Function} fn The function to wrap. - * @param {Array} transformers A list of transformer functions - * @return {Function} The wrapped function. - * @see R.converge - * @example - * - * R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81 - * R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81 - * R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32 - * R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32 - * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b)) - */ -var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) { - return curryN(transformers.length, function () { - var args = []; - var idx = 0; - while (idx < transformers.length) { - args.push(transformers[idx].call(this, arguments[idx])); - idx += 1; - } - return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length))); - }); -}); - -/** - * Reasonable analog to SQL `select` statement. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @category Relation - * @sig [k] -> [{k: v}] -> [{k: v}] - * @param {Array} props The property names to project - * @param {Array} objs The objects to query - * @return {Array} An array of objects with just the `props` properties. - * @example - * - * var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}; - * var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}; - * var kids = [abby, fred]; - * R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}] - */ -var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity - -/** - * Returns a copy of the list, sorted according to the comparator function, - * which should accept two values at a time and return a negative number if the - * first value is smaller, a positive number if it's larger, and zero if they - * are equal. Please note that this is a **copy** of the list. It does not - * modify the original. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig ((a, a) -> Number) -> [a] -> [a] - * @param {Function} comparator A sorting function :: a -> b -> Int - * @param {Array} list The list to sort - * @return {Array} a new array with its elements sorted by the comparator function. - * @example - * - * var diff = function(a, b) { return a - b; }; - * R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7] - */ -var sort = /*#__PURE__*/_curry2(function sort(comparator, list) { - return Array.prototype.slice.call(list, 0).sort(comparator); -}); - -/** - * Splits a string into an array of strings based on the given - * separator. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category String - * @sig (String | RegExp) -> String -> [String] - * @param {String|RegExp} sep The pattern. - * @param {String} str The string to separate into an array. - * @return {Array} The array of strings from `str` separated by `str`. - * @see R.join - * @example - * - * var pathComponents = R.split('/'); - * R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node'] - * - * R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd'] - */ -var split = /*#__PURE__*/invoker(1, 'split'); - -/** - * The lower case version of a string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category String - * @sig String -> String - * @param {String} str The string to lower case. - * @return {String} The lower case version of `str`. - * @see R.toUpper - * @example - * - * R.toLower('XYZ'); //=> 'xyz' - */ -var toLower = /*#__PURE__*/invoker(0, 'toLowerCase'); - -/** - * Converts an object into an array of key, value arrays. Only the object's - * own properties are used. - * Note that the order of the output array is not guaranteed to be consistent - * across different JS platforms. - * - * @func - * @memberOf R - * @since v0.4.0 - * @category Object - * @sig {String: *} -> [[String,*]] - * @param {Object} obj The object to extract from - * @return {Array} An array of key, value arrays from the object's own properties. - * @see R.fromPairs - * @example - * - * R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]] - */ -var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) { - var pairs = []; - for (var prop in obj) { - if (_has(prop, obj)) { - pairs[pairs.length] = [prop, obj[prop]]; - } - } - return pairs; -}); - -/** - * The upper case version of a string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category String - * @sig String -> String - * @param {String} str The string to upper case. - * @return {String} The upper case version of `str`. - * @see R.toLower - * @example - * - * R.toUpper('abc'); //=> 'ABC' - */ -var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase'); - -/** - * Initializes a transducer using supplied iterator function. Returns a single - * item by iterating through the list, successively calling the transformed - * iterator function and passing it an accumulator value and the current value - * from the array, and then passing the result to the next call. - * - * The iterator function receives two values: *(acc, value)*. It will be - * wrapped as a transformer to initialize the transducer. A transformer can be - * passed directly in place of an iterator function. In both cases, iteration - * may be stopped early with the [`R.reduced`](#reduced) function. - * - * A transducer is a function that accepts a transformer and returns a - * transformer and can be composed directly. - * - * A transformer is an an object that provides a 2-arity reducing iterator - * function, step, 0-arity initial value function, init, and 1-arity result - * extraction function, result. The step function is used as the iterator - * function in reduce. The result function is used to convert the final - * accumulator into the return type and in most cases is - * [`R.identity`](#identity). The init function can be used to provide an - * initial accumulator, but is ignored by transduce. - * - * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer. - * - * @func - * @memberOf R - * @since v0.12.0 - * @category List - * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a - * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. - * @param {Function} fn The iterator function. Receives two values, the accumulator and the - * current element from the array. Wrapped as transformer, if necessary, and used to - * initialize the transducer - * @param {*} acc The initial accumulator value. - * @param {Array} list The list to iterate over. - * @return {*} The final, accumulated value. - * @see R.reduce, R.reduced, R.into - * @example - * - * var numbers = [1, 2, 3, 4]; - * var transducer = R.compose(R.map(R.add(1)), R.take(2)); - * R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3] - * - * var isOdd = (x) => x % 2 === 1; - * var firstOddTransducer = R.compose(R.filter(isOdd), R.take(1)); - * R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1] - */ -var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) { - return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list); -}); - -var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; -var zeroWidth = '\u200b'; -var hasProtoTrim = typeof String.prototype.trim === 'function'; -/** - * Removes (strips) whitespace from both ends of the string. - * - * @func - * @memberOf R - * @since v0.6.0 - * @category String - * @sig String -> String - * @param {String} str The string to trim. - * @return {String} Trimmed version of `str`. - * @example - * - * R.trim(' xyz '); //=> 'xyz' - * R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z'] - */ -var _trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? function trim(str) { - var beginRx = new RegExp('^[' + ws + '][' + ws + ']*'); - var endRx = new RegExp('[' + ws + '][' + ws + ']*$'); - return str.replace(beginRx, '').replace(endRx, ''); -} : function trim(str) { - return str.trim(); -}; - -/** - * Combines two lists into a set (i.e. no duplicates) composed of the elements - * of each list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig [*] -> [*] -> [*] - * @param {Array} as The first list. - * @param {Array} bs The second list. - * @return {Array} The first and second lists concatenated, with - * duplicates removed. - * @example - * - * R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4] - */ -var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat)); - -/** - * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from - * any [Chain](https://github.com/fantasyland/fantasy-land#chain). - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig Chain c => c (c a) -> c a - * @param {*} list - * @return {*} - * @see R.flatten, R.chain - * @example - * - * R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]] - * R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6] - */ -var unnest = /*#__PURE__*/chain(_identity); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { - return typeof obj; -} : function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; -}; - - - - - - - - - - - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - - - - - -var defineProperty = function (obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; -}; - -var _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; -}; - - - - - - - - - - - - - -var objectWithoutProperties = function (obj, keys) { - var target = {}; - - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; - } - - return target; -}; - - - - - - - -var slicedToArray = function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -}(); - -// urlEncode :: Object -> String -var urlEncode = pipe(filter(function (x) { - return x !== undefined; -}), toPairs, map(function (_ref) { - var _ref2 = slicedToArray(_ref, 2), - k = _ref2[0], - v = _ref2[1]; - - return k + '=' + encodeURIComponent(v); -}), join('&')); - -// appendQueryParam :: String -> String -> String -> String -var appendQueryParam = function appendQueryParam(key, value, url) { - var _split = split('?', url), - _split2 = slicedToArray(_split, 2), - before = _split2[0], - after = _split2[1]; - - return before + '?' + (after ? after + '&' : '') + urlEncode(defineProperty({}, key, value)); -}; - -var typeCheck = function typeCheck(name, expectedType, value) { - var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); - if (type !== expectedType) { - throw new TypeError('expected ' + name + ' to be of type ' + expectedType + ' but was of type ' + type); - } -}; - -// checks that all of an arrays elements are of the given type -var typeCheckArr = function typeCheckArr(name, expectedType, arr) { - if (!Array.isArray(arr)) { - throw new TypeError('expected ' + name + ' to be an array'); - } - arr.forEach(function (value, i) { - return typeCheck(name + '[' + i + ']', expectedType, value); - }); -}; - -// checks that all of an objects values are of the given type -var typeCheckObj = function typeCheckObj(name, expectedType, obj) { - typeCheck(name, 'object', obj); - forEachObjIndexed(function (value, key) { - return typeCheck(key, expectedType, value); - }, obj); -}; - -var checkOneOf = function checkOneOf(name, values, value) { - if (!contains$1(value, values)) { - throw new TypeError('expected ' + name + ' to be one of ' + values + ' but was ' + value); - } -}; - -var unixSeconds = function unixSeconds() { - return Math.floor(Date.now() / 1000); -}; - -// pointfree debugging - -var TokenProvider = -// TODO authContext -function TokenProvider() { - var _this = this; - - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - url = _ref.url; - - classCallCheck(this, TokenProvider); - - this.fetchToken = function () { - return !_this.cacheIsStale() ? Promise.resolve(_this.cachedToken) : _this.fetchFreshToken().then(function (_ref2) { - var token = _ref2.token, - expiresIn = _ref2.expiresIn; - - _this.cache(token, expiresIn); - return token; - }); - }; - - this.fetchFreshToken = function () { - return pusherPlatform_4({ - method: 'POST', - url: appendQueryParam('user_id', _this.userId, _this.url), - body: urlEncode({ grant_type: 'client_credentials' }), - headers: { - 'content-type': 'application/x-www-form-urlencoded' - } - }).then(function (res) { - var _JSON$parse = JSON.parse(res), - token = _JSON$parse.access_token, - expiresIn = _JSON$parse.expires_in; - - return { token: token, expiresIn: expiresIn }; - }); - }; - - this.cacheIsStale = function () { - return !_this.cachedToken || unixSeconds() > _this.cacheExpiresAt; - }; - - this.cache = function (token, expiresIn) { - _this.cachedToken = token; - _this.cacheExpiresAt = unixSeconds() + expiresIn; - }; - - this.clearCache = function () { - _this.cachedToken = undefined; - _this.cacheExpiresAt = undefined; - }; - - this.setUserId = function (userId) { - _this.clearCache(); - _this.userId = userId; - }; - - typeCheck('url', 'string', url); - this.url = url; -}; - -var Store = function Store() { - var _this = this; - - classCallCheck(this, Store); - this.pendingSets = []; - this.pendingGets = []; - - this.initialize = function (initialStore) { - _this.store = clone(initialStore); - forEach(function (_ref) { - var key = _ref.key, - value = _ref.value, - resolve = _ref.resolve; - - resolve(_this.store[key] = value); - }, _this.pendingSets); - forEach(function (_ref2) { - var key = _ref2.key, - resolve = _ref2.resolve; - - resolve(_this.store[key]); - }, _this.pendingGets); - }; - - this.set = function (key, value) { - if (_this.store) { - return Promise.resolve(_this.store[key] = value); - } else { - return new Promise(function (resolve) { - _this.pendingSets.push({ key: key, value: value, resolve: resolve }); - }); - } - }; - - this.get = function (key) { - if (_this.store) { - return Promise.resolve(_this.store[key]); - } else { - return new Promise(function (resolve) { - _this.pendingGets.push({ key: key, resolve: resolve }); - }); - } - }; - - this.pop = function (key) { - return _this.get(key).then(function (value) { - delete _this.store[key]; - return value; - }); - }; - - this.snapshot = function () { - return _this.store || {}; - }; - - this.getSync = function (key) { - return _this.store ? _this.store[key] : undefined; - }; -}; - -var parseBasicRoom = function parseBasicRoom(data) { - return { - createdAt: data.created_at, - createdByUserId: data.created_by_id, - deletedAt: data.deletedAt, - id: data.id, - isPrivate: data.private, - name: data.name, - updatedAt: data.updated_at, - userIds: data.member_user_ids - }; -}; - -var parseUser = function parseUser(data) { - return { - avatarURL: data.avatar_url, - createdAt: data.created_at, - customData: data.custom_data, - id: data.id, - name: data.name, - updatedAt: data.updated_at - }; -}; - -var parsePresence = function parsePresence(data) { - return { - lastSeenAt: data.last_seen_at, - state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', - userId: data.user_id - }; -}; - -var parseBasicMessage = function parseBasicMessage(data) { - return { - id: data.id, - senderId: data.user_id, - roomId: data.room_id, - text: data.text, - createdAt: data.created_at, - updatedAt: data.updated_at - }; -}; - -var UserStore = function UserStore(_ref) { - var _this = this; - - var instance = _ref.instance, - presenceStore = _ref.presenceStore, - logger = _ref.logger; - classCallCheck(this, UserStore); - this.store = new Store(); - this.initialize = this.store.initialize; - this.set = this.store.set; - - this.get = function (userId) { - return Promise.all([_this.store.get(userId).then(function (user) { - return user || _this.fetchBasicUser(userId); - }), _this.presenceStore.get(userId)]).then(function (_ref2) { - var _ref3 = slicedToArray(_ref2, 2), - user = _ref3[0], - presence = _ref3[1]; - - return _extends({}, user, { presence: presence }); - }); - }; - - this.fetchBasicUser = function (userId) { - return _this.instance.request({ - method: 'GET', - path: '/users/' + encodeURIComponent(userId) - }).then(function (res) { - var user = parseUser(JSON.parse(res)); - _this.set(userId, user); - return user; - }).catch(function (err) { - _this.logger.warn('error fetching user information:', err); - throw err; - }); - }; - - this.fetchMissingUsers = function (userIds) { - var missing = difference(userIds, map(prop('id'), values(_this.store.snapshot()))); - if (length(missing) === 0) { - return Promise.resolve(); - } - // TODO don't make simulatneous requests for the same users (question: what - // will actually cause this situation to arise? Receiving lots of messages - // in a room from a user who is no longer a member of said room?) - return _this.instance.request({ - method: 'GET', - path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') - }).then(pipe(JSON.parse, map(parseUser), forEach(function (user) { - return _this.set(user.id, user); - }))).catch(function (err) { - _this.logger.warn('error fetching missing users:', err); - throw err; - }); - }; - - this.snapshot = function () { - return map(_this.decorate, _this.store.snapshot()); - }; - - this.getSync = function (userId) { - return _this.decorate(_this.store.getSync(userId)); - }; - - this.decorate = function (user) { - return user ? _extends({}, user, { presence: _this.presenceStore.getSync(user.id) }) : undefined; - }; - - this.instance = instance; - this.presenceStore = presenceStore; - this.logger = logger; -}; - -var Room = function () { - function Room(basicRoom, userStore) { - classCallCheck(this, Room); - - this.createdAt = basicRoom.createdAt; - this.createdByUserId = basicRoom.createdByUserId; - this.deletedAt = basicRoom.deletedAt; - this.id = basicRoom.id; - this.isPrivate = basicRoom.isPrivate; - this.name = basicRoom.name; - this.updatedAt = basicRoom.updatedAt; - this.userIds = basicRoom.userIds; - this.userStore = userStore; - } - - createClass(Room, [{ - key: 'users', - get: function get$$1() { - var _this = this; - - return filter(function (user) { - return contains$1(user.id, _this.userIds); - }, values(this.userStore.snapshot())); - } - }]); - return Room; -}(); - -var RoomStore = function RoomStore(_ref) { - var _this = this; - - var instance = _ref.instance, - userStore = _ref.userStore, - logger = _ref.logger; - classCallCheck(this, RoomStore); - this.store = new Store(); - this.initialize = this.store.initialize; - this.set = curry(function (roomId, basicRoom) { - return _this.store.set(roomId, basicRoom).then(_this.decorate).then(function (room) { - return _this.userStore.fetchMissingUsers(room.userIds).then(function () { - return room; - }); - }); - }); - - this.get = function (roomId) { - return _this.store.get(roomId).then(function (basicRoom) { - return basicRoom || _this.fetchBasicRoom(roomId).then(_this.set(roomId)); - }).then(_this.decorate); - }; - - this.pop = function (roomId) { - return _this.store.pop(roomId).then(function (basicRoom) { - return basicRoom || _this.fetchBasicRoom(roomId); - }).then(_this.decorate); - }; - - this.addUserToRoom = function (roomId, userId) { - return _this.pop(roomId).then(function (r) { - return _this.set(roomId, _extends({}, r, { userIds: uniq(append(userId, r.userIds)) })); - }); - }; - - this.removeUserFromRoom = function (roomId, userId) { - return _this.pop(roomId).then(function (r) { - return _this.set(roomId, _extends({}, r, { userIds: filter(function (id) { - return id !== userId; - }, r.userIds) })); - }); - }; - - this.update = function (roomId, updates) { - return _this.store.pop(roomId).then(function (r) { - return _this.set(roomId, mergeWith(function (x, y) { - return y || x; - }, r, updates)); - }); - }; - - this.fetchBasicRoom = function (roomId) { - return _this.instance.request({ - method: 'GET', - path: '/rooms/' + roomId - }).then(pipe(JSON.parse, parseBasicRoom)).catch(function (err) { - _this.logger.warn('error fetching details for room ' + roomId + ':', err); - }); - }; - - this.snapshot = function () { - return map(_this.decorate, _this.store.snapshot()); - }; - - this.getSync = function (roomId) { - return _this.decorate(_this.store.getSync(roomId)); - }; - - this.decorate = function (basicRoom) { - return basicRoom ? new Room(basicRoom, _this.userStore) : undefined; - }; - - this.instance = instance; - this.userStore = userStore; - this.logger = logger; -}; - -var TYPING_INDICATOR_TTL = 1500; -var TYPING_INDICATOR_LEEWAY = 500; - -var TypingIndicators = function TypingIndicators(_ref) { - var _this = this; - - var userId = _ref.userId, - instance = _ref.instance, - logger = _ref.logger; - classCallCheck(this, TypingIndicators); - - this.sendThrottledRequest = function (roomId) { - var now = Date.now(); - var sent = _this.lastSentRequests[roomId]; - if (sent && now - sent < TYPING_INDICATOR_TTL - TYPING_INDICATOR_LEEWAY) { - return Promise.resolve(); - } - _this.lastSentRequests[roomId] = now; - return _this.instance.request({ - method: 'POST', - path: '/rooms/' + roomId + '/events', - json: { - name: 'typing_start', // soon to be 'is_typing' - user_id: _this.userId - } - }).catch(function (err) { - delete _this.typingRequestSent[roomId]; - _this.logger.warn('Error sending is_typing event in room ' + roomId, err); - throw err; - }); - }; - - this.onIsTyping = function (room, user, hooks, roomHooks) { - if (!_this.timers[room.id]) { - _this.timers[room.id] = {}; - } - if (_this.timers[room.id][user.id]) { - clearTimeout(_this.timers[room.id][user.id]); - } else { - _this.onStarted(room, user, hooks, roomHooks); - } - _this.timers[room.id][user.id] = setTimeout(function () { - _this.onStopped(room, user, hooks, roomHooks); - delete _this.timers[room.id][user.id]; - }, TYPING_INDICATOR_TTL); - }; - - this.onStarted = function (room, user, hooks, roomHooks) { - if (hooks.userStartedTyping) { - hooks.userStartedTyping(room, user); - } - if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { - roomHooks[room.id].userStartedTyping(user); - } - }; - - this.onStopped = function (room, user, hooks, roomHooks) { - if (hooks.userStoppedTyping) { - hooks.userStoppedTyping(room, user); - } - if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { - roomHooks[room.id].userStoppedTyping(user); - } - }; - - this.userId = userId; - this.instance = instance; - this.logger = logger; - this.lastSentRequests = {}; - this.timers = {}; -}; - -var UserSubscription = function () { - function UserSubscription(options) { - var _this = this; - - classCallCheck(this, UserSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'initial_state': - _this.onInitialState(body.data); - break; - case 'added_to_room': - _this.onAddedToRoom(body.data); - break; - case 'removed_from_room': - _this.onRemovedFromRoom(body.data); - break; - case 'user_joined': - _this.onUserJoined(body.data); - break; - case 'user_left': - _this.onUserLeft(body.data); - break; - case 'room_updated': - _this.onRoomUpdated(body.data); - break; - case 'room_deleted': - _this.onRoomDeleted(body.data); - break; - case 'typing_start': - // soon to be 'is_typing' - _this.onIsTyping(body.data); - break; - } - }; - - this.onInitialState = function (_ref2) { - var userData = _ref2.current_user, - roomsData = _ref2.rooms; - - _this.hooks.subscriptionEstablished({ - user: parseUser(userData), - basicRooms: map(parseBasicRoom, roomsData) - }); - }; - - this.onAddedToRoom = function (_ref3) { - var roomData = _ref3.room; - - var basicRoom = parseBasicRoom(roomData); - _this.roomStore.set(basicRoom.id, basicRoom).then(function (room) { - if (_this.hooks.addedToRoom) { - _this.hooks.addedToRoom(room); - } - }); - }; - - this.onRemovedFromRoom = function (_ref4) { - var roomId = _ref4.room_id; - - _this.roomStore.pop(roomId).then(function (room) { - // room will be undefined if we left with leaveRoom - if (room && _this.hooks.removedFromRoom) { - _this.hooks.removedFromRoom(room); - } - }); - }; - - this.onUserJoined = function (_ref5) { - var roomId = _ref5.room_id, - userId = _ref5.user_id; - - _this.roomStore.addUserToRoom(roomId, userId).then(function (room) { - _this.userStore.get(userId).then(function (user) { - if (_this.hooks.userJoinedRoom) { - _this.hooks.userJoinedRoom(room, user); - } - if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userJoined) { - _this.roomSubscriptions[roomId].hooks.userJoined(user); - } - }); - }); - }; - - this.onUserLeft = function (_ref6) { - var roomId = _ref6.room_id, - userId = _ref6.user_id; - - _this.roomStore.removeUserFromRoom(roomId, userId).then(function (room) { - _this.userStore.get(userId).then(function (user) { - if (_this.hooks.userLeftRoom) { - _this.hooks.userLeftRoom(room, user); - } - if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userLeft) { - _this.roomSubscriptions[roomId].hooks.userLeft(user); - } - }); - }); - }; - - this.onRoomUpdated = function (_ref7) { - var roomData = _ref7.room; - - var updates = parseBasicRoom(roomData); - _this.roomStore.update(updates.id, updates).then(function (room) { - if (_this.hooks.roomUpdated) { - _this.hooks.roomUpdated(room); - } - }); - }; - - this.onRoomDeleted = function (_ref8) { - var roomId = _ref8.room_id; - - _this.roomStore.pop(roomId).then(function (room) { - if (room && _this.hooks.roomDeleted) { - _this.hooks.roomDeleted(room); - } - }); - }; - - this.onIsTyping = function (_ref9) { - var roomId = _ref9.room_id, - userId = _ref9.user_id; - - Promise.all([_this.roomStore.get(roomId), _this.userStore.get(userId)]).then(function (_ref10) { - var _ref11 = slicedToArray(_ref10, 2), - room = _ref11[0], - user = _ref11[1]; - - return _this.typingIndicators.onIsTyping(room, user, _this.hooks, map(prop('hooks'), _this.roomSubscriptions)); - }); - }; - - this.userId = options.userId; - this.hooks = options.hooks; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.typingIndicators = options.typingIndicators; - this.roomSubscriptions = options.roomSubscriptions; - } - - createClass(UserSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); - _this2.instance.subscribeNonResuming({ - path: '/users', - listeners: { - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return UserSubscription; -}(); - -var PresenceSubscription = function () { - function PresenceSubscription(options) { - var _this = this; - - classCallCheck(this, PresenceSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'initial_state': - _this.onInitialState(body.data); - break; - case 'presence_update': - _this.onPresenceUpdate(body.data); - break; - case 'join_room_presence_update': - _this.onJoinRoomPresenceUpdate(body.data); - break; - } - }; - - this.onInitialState = function (_ref2) { - var userStates = _ref2.user_states; - - _this.presenceStore.initialize(indexBy(prop('userId'), map(parsePresence, userStates))); - _this.hooks.subscriptionEstablished(); - }; - - this.onPresenceUpdate = function (data) { - var presence = parsePresence(data); - _this.presenceStore.set(presence.userId, presence).then(function (p) { - return _this.userStore.get(p.userId).then(function (user) { - switch (p.state) { - case 'online': - _this.onCameOnline(user); - break; - case 'offline': - _this.onWentOffline(user); - break; - } - }); - }); - }; - - this.onJoinRoomPresenceUpdate = function (_ref3) { - var userStates = _ref3.user_states; - return forEach(function (presence) { - return _this.presenceStore.set(presence.userId, presence); - }, map(parsePresence, userStates)); - }; - - this.onCameOnline = function (user) { - if (_this.hooks.userCameOnline) { - _this.hooks.userCameOnline(user); - } - compose(forEach(function (sub) { - return _this.roomStore.get(sub.roomId).then(function (room) { - if (contains$1(user.id, room.userIds)) { - sub.hooks.userCameOnlineInRoom(user); - } - }); - }), filter(function (sub) { - return sub.hooks.userCameOnlineInRoom !== undefined; - }), values)(_this.roomSubscriptions); - }; - - this.onWentOffline = function (user) { - if (_this.hooks.userWentOffline) { - _this.hooks.userWentOffline(user); - } - compose(forEach(function (sub) { - return _this.roomStore.get(sub.roomId).then(function (room) { - if (contains$1(user.id, room.userIds)) { - sub.hooks.userWentOfflineInRoom(user); - } - }); - }), filter(function (sub) { - return sub.hooks.userWentOfflineInRoom !== undefined; - }), values)(_this.roomSubscriptions); - }; - - this.userId = options.userId; - this.hooks = options.hooks; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.presenceStore = options.presenceStore; - this.roomSubscriptions = options.roomSubscriptions; - } - - createClass(PresenceSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); - _this2.instance.subscribeNonResuming({ - path: '/users/' + encodeURIComponent(_this2.userId) + '/presence', - listeners: { - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return PresenceSubscription; -}(); - -var Message = function () { - function Message(basicMessage, userStore, roomStore) { - classCallCheck(this, Message); - - this.id = basicMessage.id; - this.senderId = basicMessage.senderId; - this.roomId = basicMessage.roomId; - this.text = basicMessage.text; - this.createdAt = basicMessage.createdAt; - this.updatedAt = basicMessage.updatedAt; - this.userStore = userStore; - this.roomStore = roomStore; - } - - createClass(Message, [{ - key: "sender", - get: function get$$1() { - return this.userStore.getSync(this.senderId); - } - }, { - key: "room", - get: function get$$1() { - return this.roomStore.getSync(this.roomId); - } - }]); - return Message; -}(); - -var RoomSubscription = function () { - function RoomSubscription(options) { - var _this = this; - - classCallCheck(this, RoomSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'new_message': - _this.onNewMessage(body.data); - break; - } - }; - - this.onNewMessage = function (data) { - var pending = { - message: new Message(parseBasicMessage(data), _this.userStore, _this.roomStore), - ready: false - }; - _this.messageBuffer.push(pending); - _this.userStore.fetchMissingUsers([pending.message.senderId]).catch(function (err) { - _this.logger.error('error fetching missing user information:', err); - }).then(function () { - pending.ready = true; - _this.flushBuffer(); - }); - }; - - this.flushBuffer = function () { - while (!isEmpty(_this.messageBuffer) && head(_this.messageBuffer).ready) { - var message = _this.messageBuffer.shift().message; - if (_this.hooks.newMessage) { - _this.hooks.newMessage(message); - } - } - }; - - this.roomId = options.roomId; - this.hooks = options.hooks; - this.messageLimit = options.messageLimit; - this.userId = options.userId; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.messageBuffer = []; // { message, ready } - } - - createClass(RoomSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.instance.subscribeNonResuming({ - path: '/rooms/' + _this2.roomId + '?' + urlEncode({ - message_limit: _this2.messageLimit - }), - listeners: { - onOpen: resolve, - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return RoomSubscription; -}(); - -var CurrentUser = function () { - function CurrentUser(_ref) { - var _this = this; - - var id = _ref.id, - apiInstance = _ref.apiInstance; - classCallCheck(this, CurrentUser); - - this.isTypingIn = function (roomId) { - typeCheck('roomId', 'number', roomId); - return _this.typingIndicators.sendThrottledRequest(roomId); - }; - - this.createRoom = function () { - var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - var name = _ref2.name, - addUserIds = _ref2.addUserIds, - rest = objectWithoutProperties(_ref2, ['name', 'addUserIds']); - - name && typeCheck('name', 'string', name); - addUserIds && typeCheckArr('addUserIds', 'string', addUserIds); - return _this.apiInstance.request({ - method: 'POST', - path: '/rooms', - json: { - created_by_id: _this.id, - name: name, - private: !!rest.private, // private is a reserved word in strict mode! - user_ids: addUserIds - } - }).then(function (res) { - var basicRoom = parseBasicRoom(JSON.parse(res)); - return _this.roomStore.set(basicRoom.id, basicRoom); - }).catch(function (err) { - _this.logger.warn('error creating room:', err); - throw err; - }); - }; - - this.getJoinableRooms = function () { - return _this.apiInstance.request({ - method: 'GET', - path: '/users/' + encodeURIComponent(_this.id) + '/rooms?joinable=true' - }).then(pipe(JSON.parse, map(parseBasicRoom))).catch(function (err) { - _this.logger.warn('error getting joinable rooms:', err); - throw err; - }); - }; - - this.getAllRooms = function () { - return _this.getJoinableRooms().then(concat(_this.rooms)); - }; - - this.joinRoom = function (roomId) { - typeCheck('roomId', 'number', roomId); - if (_this.isMemberOf(roomId)) { - return _this.roomStore.get(roomId); - } - return _this.apiInstance.request({ - method: 'POST', - path: '/users/' + encodeURIComponent(_this.id) + '/rooms/' + roomId + '/join' - }).then(function (res) { - var basicRoom = parseBasicRoom(JSON.parse(res)); - return _this.roomStore.set(basicRoom.id, basicRoom); - }).catch(function (err) { - _this.logger.warn('error joining room ' + roomId + ':', err); - throw err; - }); - }; - - this.leaveRoom = function (roomId) { - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'POST', - path: '/users/' + encodeURIComponent(_this.id) + '/rooms/' + roomId + '/leave' - }).then(function () { - return _this.roomStore.pop(roomId); - }).catch(function (err) { - _this.logger.warn('error joining room ' + roomId + ':', err); - throw err; - }); - }; - - this.addUser = function (userId, roomId) { - typeCheck('userId', 'string', userId); - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'PUT', - path: '/rooms/' + roomId + '/users/add', - json: { - user_ids: [userId] - } - }).then(function () { - return _this.roomStore.addUserToRoom(roomId, userId); - }).catch(function (err) { - _this.logger.warn('error adding user ' + userId + ' to room ' + roomId + ':', err); - throw err; - }); - }; - - this.removeUser = function (userId, roomId) { - typeCheck('userId', 'string', userId); - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'PUT', - path: '/rooms/' + roomId + '/users/remove', - json: { - user_ids: [userId] - } - }).then(function () { - return _this.roomStore.removeUserFromRoom(roomId, userId); - }).catch(function (err) { - _this.logger.warn('error removing user ' + userId + ' from room ' + roomId + ':', err); - throw err; - }); - }; - - this.sendMessage = function () { - var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - text = _ref3.text, - roomId = _ref3.roomId; - - typeCheck('text', 'string', text); - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'POST', - path: '/rooms/' + roomId + '/messages', - json: { text: text } - }).then(pipe(JSON.parse, prop('message_id'))).catch(function (err) { - _this.logger.warn('error sending message to room ' + roomId + ':', err); - throw err; - }); - }; - - this.fetchMessages = function (roomId) { - var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - initialId = _ref4.initialId, - limit = _ref4.limit, - direction = _ref4.direction; - - typeCheck('roomId', 'number', roomId); - initialId && typeCheck('initialId', 'number', initialId); - limit && typeCheck('limit', 'number', limit); - direction && checkOneOf('direction', ['older', 'newer'], direction); - return _this.apiInstance.request({ - method: 'GET', - path: '/rooms/' + roomId + '/messages?' + urlEncode({ - initial_id: initialId, - limit: limit, - direction: direction - }) - }).then(function (res) { - var messages = map(compose(_this.decorateMessage, parseBasicMessage), JSON.parse(res)); - return _this.userStore.fetchMissingUsers(uniq(map(prop('senderId'), messages))).then(function () { - return sort(function (x, y) { - return x.id - y.id; - }, messages); - }); - }).catch(function (err) { - _this.logger.warn('error fetching messages from room ' + roomId + ':', err); - throw err; - }); - }; - - this.subscribeToRoom = function (roomId) { - var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var messageLimit = arguments[2]; - - typeCheck('roomId', 'number', roomId); - typeCheckObj('hooks', 'function', hooks); - messageLimit && typeCheck('messageLimit', 'number', messageLimit); - // TODO what is the desired behaviour if there is already a subscription to - // this room? Close the old one? Throw an error? Merge the hooks? - _this.roomSubscriptions[roomId] = new RoomSubscription({ - roomId: roomId, - hooks: hooks, - messageLimit: messageLimit, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - logger: _this.logger - }); - return _this.joinRoom(roomId).then(function (room) { - return _this.roomSubscriptions[roomId].connect().then(function () { - return room; - }); - }).catch(function (err) { - return _this.logger.error('error subscribing to room ' + roomId, err); - }); - }; - - this.isMemberOf = function (roomId) { - return contains$1(roomId, map(prop('id'), _this.rooms)); - }; - - this.decorateMessage = function (basicMessage) { - return new Message(basicMessage, _this.userStore, _this.roomStore); - }; - - this.establishUserSubscription = function (hooks) { - _this.userSubscription = new UserSubscription({ - hooks: hooks, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - typingIndicators: _this.typingIndicators, - roomSubscriptions: _this.roomSubscriptions - }); - return _this.userSubscription.connect().then(function (_ref5) { - var user = _ref5.user, - basicRooms = _ref5.basicRooms; - - _this.avatarURL = user.avatarURL; - _this.createdAt = user.createdAt; - _this.customData = user.customData; - _this.name = user.name; - _this.updatedAt = user.updatedAt; - _this.roomStore.initialize(indexBy(prop('id'), basicRooms)); - }).then(_this.initializeUserStore); - }; - - this.establishPresenceSubscription = function (hooks) { - _this.presenceSubscription = new PresenceSubscription({ - hooks: hooks, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - presenceStore: _this.presenceStore, - roomSubscriptions: _this.roomSubscriptions - }); - return _this.presenceSubscription.connect(); - }; - - this.initializeUserStore = function () { - return _this.userStore.fetchMissingUsers(uniq(chain(prop('userIds'), _this.rooms))).catch(function (err) { - _this.logger.warn('error fetching initial user information:', err); - }).then(function () { - _this.userStore.initialize({}); - }); - }; - - this.id = id; - this.apiInstance = apiInstance; - this.logger = apiInstance.logger; - this.presenceStore = new Store(); - this.userStore = new UserStore({ - instance: this.apiInstance, - presenceStore: this.presenceStore, - logger: this.logger - }); - this.roomStore = new RoomStore({ - instance: this.apiInstance, - userStore: this.userStore, - logger: this.logger - }); - this.typingIndicators = new TypingIndicators({ - userId: this.id, - instance: this.apiInstance, - logger: this.logger - }); - this.roomSubscriptions = {}; - } - - /* public */ - - createClass(CurrentUser, [{ - key: 'rooms', - get: function get$$1() { - return values(this.roomStore.snapshot()); - } - }, { - key: 'users', - get: function get$$1() { - return values(this.userStore.snapshot()); - } - - // TODO attachments - - - /* internal */ - - }]); - return CurrentUser; -}(); - -var ChatManager = function ChatManager() { - var _this = this; - - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - var instanceLocator = _ref.instanceLocator, - tokenProvider = _ref.tokenProvider, - userId = _ref.userId, - options = objectWithoutProperties(_ref, ['instanceLocator', 'tokenProvider', 'userId']); - classCallCheck(this, ChatManager); - - this.connect = function () { - var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - typeCheckObj('hooks', 'function', hooks); - var currentUser = new CurrentUser({ - id: _this.userId, - apiInstance: _this.apiInstance - }); - return Promise.all([currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) - // currentUser.initializeCursorStore() - ]).then(function () { - return currentUser; - }); - }; - - typeCheck('instanceLocator', 'string', instanceLocator); - typeCheck('tokenProvider', 'object', tokenProvider); - typeCheck('tokenProvider.fetchToken', 'function', tokenProvider.fetchToken); - typeCheck('userId', 'string', userId); - var cluster = split(':', instanceLocator)[1]; - if (cluster === undefined) { - throw new TypeError('expected instanceLocator to be of the format x:y:z, but was ' + instanceLocator); - } - var baseClient = options.baseClient || new pusherPlatform_1({ - host: cluster + '.' + pusherPlatform_2, - logger: options.logger - }); - if (typeof tokenProvider.setUserId === 'function') { - tokenProvider.setUserId(userId); - } - var instanceOptions = { - client: baseClient, - locator: instanceLocator, - logger: options.logger, - tokenProvider: tokenProvider - }; - this.apiInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit', - serviceVersion: 'v1' - }, instanceOptions)); - this.filesInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit_files', - serviceVersion: 'v1' - }, instanceOptions)); - this.cursorsInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit_cursors', - serviceVersion: 'v1' - }, instanceOptions)); - this.userId = userId; -}; - -var main = { TokenProvider: TokenProvider, ChatManager: ChatManager }; - -return main; - -}))); From 20fcb36141aa667107a0ac497b4bc040fcc289aa Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Feb 2018 17:58:01 +0000 Subject: [PATCH 51/99] simplify appendQueryParam --- src/utils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/utils.js b/src/utils.js index e293443..03a7634 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,7 +5,6 @@ import { join, map, pipe, - split, toPairs } from 'ramda' @@ -19,8 +18,8 @@ export const urlEncode = pipe( // appendQueryParam :: String -> String -> String -> String export const appendQueryParam = (key, value, url) => { - const [ before, after ] = split('?', url) - return before + '?' + (after ? after + '&' : '') + urlEncode({ [key]: value }) + const separator = contains('?', url) ? '&' : '?' + return url + separator + urlEncode({ [key]: value }) } export const typeCheck = (name, expectedType, value) => { From 1b13479316c321063240e49beb4efbe8ddcff776 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 14 Feb 2018 10:23:42 +0000 Subject: [PATCH 52/99] joining -> leaving --- src/current-user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/current-user.js b/src/current-user.js index f42a123..227c31b 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -137,7 +137,7 @@ export class CurrentUser { }) .then(() => this.roomStore.pop(roomId)) .catch(err => { - this.logger.warn(`error joining room ${roomId}:`, err) + this.logger.warn(`error leaving room ${roomId}:`, err) throw err }) } From 1e3e6d904d634b2a3e12619a19f43452b9fbda28 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 14 Feb 2018 10:46:41 +0000 Subject: [PATCH 53/99] encode userId once at construction --- src/current-user.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 227c31b..0b6b6bf 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -32,6 +32,7 @@ import { Message } from './message' export class CurrentUser { constructor ({ id, apiInstance }) { this.id = id + this.encodedId = encodeURIComponent(this.id) this.apiInstance = apiInstance this.logger = apiInstance.logger this.presenceStore = new Store() @@ -95,7 +96,7 @@ export class CurrentUser { return this.apiInstance .request({ method: 'GET', - path: `/users/${encodeURIComponent(this.id)}/rooms?joinable=true` + path: `/users/${this.encodedId}/rooms?joinable=true` }) .then(pipe(JSON.parse, map(parseBasicRoom))) .catch(err => { @@ -116,7 +117,7 @@ export class CurrentUser { return this.apiInstance .request({ method: 'POST', - path: `/users/${encodeURIComponent(this.id)}/rooms/${roomId}/join` + path: `/users/${this.encodedId}/rooms/${roomId}/join` }) .then(res => { const basicRoom = parseBasicRoom(JSON.parse(res)) @@ -133,7 +134,7 @@ export class CurrentUser { return this.apiInstance .request({ method: 'POST', - path: `/users/${encodeURIComponent(this.id)}/rooms/${roomId}/leave` + path: `/users/${this.encodedId}/rooms/${roomId}/leave` }) .then(() => this.roomStore.pop(roomId)) .catch(err => { From 0cf155d93ec455821714ee11704481bd133db073 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 14 Feb 2018 15:24:03 +0000 Subject: [PATCH 54/99] introduce slight delay before calling isTypingIn and leave FIXME for further investigation --- tests/main.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/main.js b/tests/main.js index b12c49f..7676b02 100644 --- a/tests/main.js +++ b/tests/main.js @@ -304,7 +304,10 @@ test('typing indicators (user sub)', t => { }), fetchUser(t, 'bob') ]) - .then(([alice, bob]) => bob.isTypingIn(bobsRoom.id)) + // FIXME This test (and the corresponding room sub one) occasionally fail if + // isTypingIn is called without this timeout. It would seem that there is a + // race condition *somewhere*. + .then(([alice, bob]) => setTimeout(() => bob.isTypingIn(bobsRoom.id), 1000)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -735,7 +738,10 @@ test('typing indicators', t => { })), fetchUser(t, 'carol') ]) - .then(([x, carol]) => carol.isTypingIn(bobsRoom.id)) + // FIXME This test (and the corresponding user sub one) occasionally fail if + // isTypingIn is called without this timeout. It would seem that there is a + // race condition *somewhere*. + .then(([x, carol]) => setTimeout(() => carol.isTypingIn(bobsRoom.id), 1000)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From a82a52b4eab2e74e1890f4e8d208a6664fd0bfc9 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 14 Feb 2018 15:31:40 +0000 Subject: [PATCH 55/99] user[CameOnline|WentOffline]InRoom -> user[CameOnline|WentOffline] --- src/presence-subscription.js | 8 ++++---- tests/main.js | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/presence-subscription.js b/src/presence-subscription.js index 550dfb9..6ef1e2e 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -85,10 +85,10 @@ export class PresenceSubscription { compose( forEach(sub => this.roomStore.get(sub.roomId).then(room => { if (contains(user.id, room.userIds)) { - sub.hooks.userCameOnlineInRoom(user) + sub.hooks.userCameOnline(user) } })), - filter(sub => sub.hooks.userCameOnlineInRoom !== undefined), + filter(sub => sub.hooks.userCameOnline !== undefined), values )(this.roomSubscriptions) } @@ -100,10 +100,10 @@ export class PresenceSubscription { compose( forEach(sub => this.roomStore.get(sub.roomId).then(room => { if (contains(user.id, room.userIds)) { - sub.hooks.userWentOfflineInRoom(user) + sub.hooks.userWentOffline(user) } })), - filter(sub => sub.hooks.userWentOfflineInRoom !== undefined), + filter(sub => sub.hooks.userWentOffline !== undefined), values )(this.roomSubscriptions) } diff --git a/tests/main.js b/tests/main.js index 7676b02..d57ccb4 100644 --- a/tests/main.js +++ b/tests/main.js @@ -704,8 +704,7 @@ test(`user joined hook [Carol joins Bob's room]`, t => { test('user came online hook', t => { fetchUser(t, 'alice') .then(alice => alice.subscribeToRoom(bobsRoom.id, { - // FIXME inconsistent naming - userCameOnlineInRoom: once(user => { + userCameOnline: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.end() From 2985a7684887d23dbc0badf2811fd84f753ecc91 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 14 Feb 2018 15:57:24 +0000 Subject: [PATCH 56/99] callRelevantHooks --- src/presence-subscription.js | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/presence-subscription.js b/src/presence-subscription.js index 6ef1e2e..dabb4ce 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -78,32 +78,21 @@ export class PresenceSubscription { map(parsePresence, userStates) ) - onCameOnline = user => { - if (this.hooks.userCameOnline) { - this.hooks.userCameOnline(user) - } - compose( - forEach(sub => this.roomStore.get(sub.roomId).then(room => { - if (contains(user.id, room.userIds)) { - sub.hooks.userCameOnline(user) - } - })), - filter(sub => sub.hooks.userCameOnline !== undefined), - values - )(this.roomSubscriptions) - } + onCameOnline = user => this.callRelevantHooks('userCameOnline', user) + + onWentOffline = user => this.callRelevantHooks('userWentOffline', user) - onWentOffline = user => { - if (this.hooks.userWentOffline) { - this.hooks.userWentOffline(user) + callRelevantHooks = (hookName, user) => { + if (this.hooks[hookName]) { + this.hooks[hookName](user) } compose( forEach(sub => this.roomStore.get(sub.roomId).then(room => { if (contains(user.id, room.userIds)) { - sub.hooks.userWentOffline(user) + sub.hooks[hookName](user) } })), - filter(sub => sub.hooks.userWentOffline !== undefined), + filter(sub => sub.hooks[hookName] !== undefined), values )(this.roomSubscriptions) } From 3fc5c70585804ae1727e288e0fe56e7a13f6a88e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 20 Feb 2018 16:37:41 +0000 Subject: [PATCH 57/99] attachments --- src/chat-manager.js | 3 ++- src/current-user.js | 55 +++++++++++++++++++++++++++++++++++++++------ src/message.js | 1 + src/parsers.js | 11 ++++++++- src/utils.js | 7 ++++++ tests/main.js | 47 +++++++++++++++++++++++++++++++++++--- 6 files changed, 112 insertions(+), 12 deletions(-) diff --git a/src/chat-manager.js b/src/chat-manager.js index c2fb949..60b386c 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -51,7 +51,8 @@ export class ChatManager { typeCheckObj('hooks', 'function', hooks) const currentUser = new CurrentUser({ id: this.userId, - apiInstance: this.apiInstance + apiInstance: this.apiInstance, + filesInstance: this.filesInstance }) return Promise.all([ currentUser.establishUserSubscription(hooks), diff --git a/src/current-user.js b/src/current-user.js index 0b6b6bf..e7a21bb 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -30,10 +30,11 @@ import { RoomSubscription } from './room-subscription' import { Message } from './message' export class CurrentUser { - constructor ({ id, apiInstance }) { + constructor ({ id, apiInstance, filesInstance }) { this.id = id this.encodedId = encodeURIComponent(this.id) this.apiInstance = apiInstance + this.filesInstance = filesInstance this.logger = apiInstance.logger this.presenceStore = new Store() this.userStore = new UserStore({ @@ -182,16 +183,25 @@ export class CurrentUser { }) } - // TODO attachments - sendMessage = ({ text, roomId } = {}) => { + sendMessage = ({ text, roomId, attachment }) => { typeCheck('text', 'string', text) typeCheck('roomId', 'number', roomId) - return this.apiInstance - .request({ + return new Promise((resolve, reject) => { + if (attachment !== undefined && isDataAttachment(attachment)) { + resolve(this.uploadDataAttachment(roomId, attachment)) + } else if (attachment !== undefined && isLinkAttachment(attachment)) { + resolve({ resource_link: attachment.link, type: attachment.type }) + } else if (attachment !== undefined) { + reject(new TypeError('attachment was malformed')) + } else { + resolve() + } + }) + .then(attachment => this.apiInstance.request({ method: 'POST', path: `/rooms/${roomId}/messages`, - json: { text } - }) + json: { text, attachment } + })) .then(pipe(JSON.parse, prop('message_id'))) .catch(err => { this.logger.warn(`error sending message to room ${roomId}:`, err) @@ -254,6 +264,19 @@ export class CurrentUser { /* internal */ + uploadDataAttachment = (roomId, { file, name }) => { + // TODO some validation on allowed file names? + // TODO polyfill FormData? + const body = new FormData() // eslint-disable-line no-undef + body.append('file', file, name) + return this.filesInstance.request({ + method: 'POST', + path: `/rooms/${roomId}/files/${name}`, + body + }) + .then(JSON.parse) + } + isMemberOf = roomId => contains(roomId, map(prop('id'), this.rooms)) decorateMessage = basicMessage => new Message( @@ -307,3 +330,21 @@ export class CurrentUser { }) } } + +const isDataAttachment = ({ file, name }) => { + if (file === undefined || name === undefined) { + return false + } + typeCheck('attachment.file', 'object', file) + typeCheck('attachment.name', 'string', name) + return true +} + +const isLinkAttachment = ({ link, type }) => { + if (link === undefined || type === undefined) { + return false + } + typeCheck('attachment.link', 'string', link) + typeCheck('attachment.type', 'string', type) + return true +} diff --git a/src/message.js b/src/message.js index 930fc96..988e927 100644 --- a/src/message.js +++ b/src/message.js @@ -4,6 +4,7 @@ export class Message { this.senderId = basicMessage.senderId this.roomId = basicMessage.roomId this.text = basicMessage.text + this.attachment = basicMessage.attachment this.createdAt = basicMessage.createdAt this.updatedAt = basicMessage.updatedAt this.userStore = userStore diff --git a/src/parsers.js b/src/parsers.js index 9812179..d478acd 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -1,5 +1,7 @@ import { contains } from 'ramda' +import { extractQueryParams } from './utils' + export const parseBasicRoom = data => ({ createdAt: data.created_at, createdByUserId: data.created_by_id, @@ -32,5 +34,12 @@ export const parseBasicMessage = data => ({ roomId: data.room_id, text: data.text, createdAt: data.created_at, - updatedAt: data.updated_at + updatedAt: data.updated_at, + attachment: data.attachment && parseAttachment(data.attachment) +}) + +const parseAttachment = data => ({ + link: data.resource_link, + type: data.type, + fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' }) diff --git a/src/utils.js b/src/utils.js index 03a7634..330f3c6 100644 --- a/src/utils.js +++ b/src/utils.js @@ -2,9 +2,11 @@ import { contains, filter, forEachObjIndexed, + fromPairs, join, map, pipe, + split, toPairs } from 'ramda' @@ -22,6 +24,11 @@ export const appendQueryParam = (key, value, url) => { return url + separator + urlEncode({ [key]: value }) } +export const extractQueryParams = url => + contains('?', url) ? queryStringToObj(split('?', url)[1]) : {} + +const queryStringToObj = pipe(split('&'), map(split('=')), fromPairs) + export const typeCheck = (name, expectedType, value) => { const type = typeof value if (type !== expectedType) { diff --git a/tests/main.js b/tests/main.js index d57ccb4..2c3afe8 100644 --- a/tests/main.js +++ b/tests/main.js @@ -82,17 +82,17 @@ const sendMessages = (user, room, texts) => length(texts) === 0 // knowledge that we'll always be starting with a blank slate next time test('[teardown] destroy Alice', t => { - server.deleteUser('alice').then(() => t.end()).catch(err => t.end(err)) + server.deleteUser('alice').then(() => t.end()).catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) test('[teardown] destroy Bob', t => { - server.deleteUser('bob').then(() => t.end()).catch(err => t.end(err)) + server.deleteUser('bob').then(() => t.end()).catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) test('[teardown] destroy Carol', t => { - server.deleteUser('carol').then(() => t.end()).catch(err => t.end(err)) + server.deleteUser('carol').then(() => t.end()).catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -651,6 +651,47 @@ test('subscribe to room and receive sent messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) +test('send message with malformed attachment fails', t => { + fetchUser(t, 'alice') + .then(alice => alice.sendMessage({ + roomId: bobsRoom.id, + text: 'should fail', + attachment: { some: 'rubbish' } + })) + .catch(err => { + t.true(toString(err).match(/attachment/), 'attachment error') + t.end() + }) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test(`send message with link attachment [sends one message to Bob's room]`, t => { + fetchUser(t, 'alice') + .then(alice => alice.sendMessage({ + roomId: bobsRoom.id, + text: 'see attached', + attachment: { link: 'https://cataas.com/cat', type: 'image' } + })) + .then(() => t.end()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('receive message with link attachment', t => { + fetchUser(t, 'alice') + .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 1 })) + .then(([message]) => { + t.equal(message.text, 'see attached') + t.deepEqual(message.attachment, { + link: 'https://cataas.com/cat', + type: 'image', + fetchRequired: false + }) + t.end() + }) + t.timeoutAfter(TEST_TIMEOUT) +}) + test('[setup] create Carol', t => { server.createUser('carol', 'Carol') .then(() => server.createRoom('carol', { name: `Carol's room` })) From 69d770313f4af2a809270e183240c781cb5e9f04 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 20 Feb 2018 16:39:50 +0000 Subject: [PATCH 58/99] dist --- dist/web/chatkit.js | 6825 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6825 insertions(+) create mode 100644 dist/web/chatkit.js diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js new file mode 100644 index 0000000..8bf5868 --- /dev/null +++ b/dist/web/chatkit.js @@ -0,0 +1,6825 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Chatkit = factory()); +}(this, (function () { 'use strict'; + +var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + + +function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var pusherPlatform = createCommonjsModule(function (module, exports) { +(function webpackUniversalModuleDefinition(root, factory) { + module.exports = factory(); +})(commonjsGlobal, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 10); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +function responseToHeadersObject(headerStr) { + var headers = {}; + if (!headerStr) { + return headers; + } + var headerPairs = headerStr.split('\u000d\u000a'); + for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { + var headerPair = headerPairs_1[_i]; + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) { + var key = headerPair.substring(0, index); + var val = headerPair.substring(index + 2); + headers[key] = val; + } + } + return headers; +} +exports.responseToHeadersObject = responseToHeadersObject; +var ErrorResponse = (function () { + function ErrorResponse(statusCode, headers, info) { + this.statusCode = statusCode; + this.headers = headers; + this.info = info; + } + ErrorResponse.fromXHR = function (xhr) { + var errorInfo = xhr.responseText; + try { + errorInfo = JSON.parse(xhr.responseText); + } + catch (e) { + } + return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); + }; + return ErrorResponse; +}()); +exports.ErrorResponse = ErrorResponse; +var NetworkError = (function () { + function NetworkError(error) { + this.error = error; + } + return NetworkError; +}()); +exports.NetworkError = NetworkError; +var XhrReadyState; +(function (XhrReadyState) { + XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; + XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; + XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; + XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; + XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; +})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var LogLevel; +(function (LogLevel) { + LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; + LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; + LogLevel[LogLevel["INFO"] = 3] = "INFO"; + LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; + LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; +})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); +var ConsoleLogger = (function () { + function ConsoleLogger(threshold) { + if (threshold === void 0) { threshold = 2; } + this.threshold = threshold; + var groups = Array(); + var hr = '--------------------------------------------------------------------------------'; + if (!window.console.group) { + window.console.group = function (label) { + groups.push(label); + window.console.log('%c \nBEGIN GROUP: %c', hr, label); + }; + } + if (!window.console.groupEnd) { + window.console.groupEnd = function () { + window.console.log('END GROUP: %c\n%c', groups.pop(), hr); + }; + } + } + ConsoleLogger.prototype.verbose = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.log, LogLevel.VERBOSE, items); + }; + ConsoleLogger.prototype.debug = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.log, LogLevel.DEBUG, items); + }; + ConsoleLogger.prototype.info = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.info, LogLevel.INFO, items); + }; + ConsoleLogger.prototype.warn = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.warn, LogLevel.WARNING, items); + }; + ConsoleLogger.prototype.error = function () { + var items = []; + for (var _i = 0; _i < arguments.length; _i++) { + items[_i] = arguments[_i]; + } + this.log(window.console.error, LogLevel.ERROR, items); + }; + ConsoleLogger.prototype.log = function (logFunction, level, items) { + var _this = this; + if (level >= this.threshold) { + var loggerSignature_1 = "Logger." + LogLevel[level]; + if (items.length > 1) { + window.console.group(); + items.forEach(function (item) { + _this.errorAwareLog(logFunction, item, loggerSignature_1); + }); + window.console.groupEnd(); + } + else { + this.errorAwareLog(logFunction, items[0], loggerSignature_1); + } + } + }; + ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { + if (item.info && item.info.error_uri) { + var errorDesc = item.info.error_description; + var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; + logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); + } + else { + logFunction(loggerSignature + ": ", item); + } + }; + return ConsoleLogger; +}()); +exports.ConsoleLogger = ConsoleLogger; +var EmptyLogger = (function () { + function EmptyLogger() { + } + EmptyLogger.prototype.verbose = function (message, error) { }; + EmptyLogger.prototype.debug = function (message, error) { }; + EmptyLogger.prototype.info = function (message, error) { }; + EmptyLogger.prototype.warn = function (message, error) { }; + EmptyLogger.prototype.error = function (message, error) { }; + return EmptyLogger; +}()); +exports.EmptyLogger = EmptyLogger; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createRetryStrategyOptionsOrDefault = function (options) { + var initialTimeoutMillis = options.initialTimeoutMillis || 1000; + var maxTimeoutMillis = options.maxTimeoutMillis || 5000; + var limit = -1; + if (options.limit !== undefined && options.limit != null) { + limit = options.limit; + } + var increaseTimeout; + if (options.increaseTimeout !== undefined) { + increaseTimeout = options.increaseTimeout; + } + else { + increaseTimeout = function (currentTimeout) { + if (currentTimeout * 2 > maxTimeoutMillis) { + return maxTimeoutMillis; + } + else { + return currentTimeout * 2; + } + }; + } + return { + increaseTimeout: increaseTimeout, + initialTimeoutMillis: initialTimeoutMillis, + limit: limit, + maxTimeoutMillis: maxTimeoutMillis, + }; +}; +var Retry = (function () { + function Retry(waitTimeMillis) { + this.waitTimeMillis = waitTimeMillis; + } + return Retry; +}()); +exports.Retry = Retry; +var DoNotRetry = (function () { + function DoNotRetry(error) { + this.error = error; + } + return DoNotRetry; +}()); +exports.DoNotRetry = DoNotRetry; +var requestMethodIsSafe = function (method) { + method = method.toUpperCase(); + return (method === 'GET' || + method === 'HEAD' || + method === 'OPTIONS' || + method === 'SUBSCRIBE'); +}; +var RetryResolution = (function () { + function RetryResolution(options, logger, retryUnsafeRequests) { + this.options = options; + this.logger = logger; + this.retryUnsafeRequests = retryUnsafeRequests; + this.currentRetryCount = 0; + this.initialTimeoutMillis = options.initialTimeoutMillis; + this.maxTimeoutMillis = options.maxTimeoutMillis; + this.limit = options.limit; + this.increaseTimeoutFunction = options.increaseTimeout; + this.currentBackoffMillis = this.initialTimeoutMillis; + } + RetryResolution.prototype.attemptRetry = function (error) { + this.logger.verbose(this.constructor.name + ": Error received", error); + if (this.currentRetryCount >= this.limit && this.limit >= 0) { + this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); + return new DoNotRetry(error); + } + if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { + this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); + return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); + } + if (error instanceof network_1.NetworkError || + (error instanceof network_1.ErrorResponse && + requestMethodIsSafe(error.headers['Request-Method'])) || + this.retryUnsafeRequests) { + return this.shouldSafeRetry(error); + } + if (error instanceof network_1.NetworkError) { + return this.shouldSafeRetry(error); + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.shouldSafeRetry = function (error) { + if (error instanceof network_1.NetworkError) { + this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); + return new Retry(this.calulateMillisToRetry()); + } + else if (error instanceof network_1.ErrorResponse) { + if (error.statusCode >= 500 && error.statusCode < 600) { + this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); + return new Retry(this.calulateMillisToRetry()); + } + } + this.logger.verbose(this.constructor.name + ": Error is not retryable", error); + return new DoNotRetry(error); + }; + RetryResolution.prototype.calulateMillisToRetry = function () { + this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); + this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); + return this.currentBackoffMillis; + }; + return RetryResolution; +}()); +exports.RetryResolution = RetryResolution; + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var logger_1 = __webpack_require__(1); +var request_1 = __webpack_require__(4); +var resuming_subscription_1 = __webpack_require__(5); +var retrying_subscription_1 = __webpack_require__(6); +var subscribe_strategy_1 = __webpack_require__(11); +var subscription_1 = __webpack_require__(12); +var token_providing_subscription_1 = __webpack_require__(7); +var http_1 = __webpack_require__(13); +var websocket_1 = __webpack_require__(14); +var transports_1 = __webpack_require__(8); +var BaseClient = (function () { + function BaseClient(options) { + this.options = options; + this.host = options.host.replace(/(\/)+$/, ''); + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.websocketTransport = new websocket_1.default(this.host); + this.httpTransport = new http_1.default(this.host, options.encrypted); + } + BaseClient.prototype.request = function (options, tokenParams) { + var _this = this; + if (options.tokenProvider) { + return options.tokenProvider + .fetchToken(tokenParams) + .then(function (token) { + if (options.headers !== undefined) { + options.headers['Authorization'] = "Bearer " + token; + } + else { + options.headers = (_a = {}, _a['Authorization'] = "Bearer " + token, _a); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + var _a; + }) + .catch(function (error) { + _this.logger.error(error); + }); + } + return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); + }; + BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { + var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); + var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); + var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); + var opened = false; + return subscriptionStrategy({ + onEnd: subscribeStrategyListeners.onEnd, + onError: subscribeStrategyListeners.onError, + onEvent: subscribeStrategyListeners.onEvent, + onOpen: function (headers) { + if (!opened) { + opened = true; + subscribeStrategyListeners.onOpen(headers); + } + completeListeners.onSubscribe(); + }, + onRetrying: subscribeStrategyListeners.onRetrying, + }, headers); + }; + return BaseClient; +}()); +exports.BaseClient = BaseClient; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +function executeNetworkRequest(createXhr, options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); + sendBody(xhr, options); + }); +} +exports.executeNetworkRequest = executeNetworkRequest; +function sendBody(xhr, options) { + if (options.json) { + xhr.send(JSON.stringify(options.json)); + } + else { + xhr.send(options.body); + } +} +function sendRawRequest(options) { + return new Promise(function (resolve, reject) { + var xhr = attachOnReadyStateChangeHandler(new window.XMLHttpRequest(), resolve, reject); + xhr.open(options.method.toUpperCase(), options.url, true); + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + xhr.send(options.body); + }); +} +exports.sendRawRequest = sendRawRequest; +function attachOnReadyStateChangeHandler(xhr, resolve, reject) { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.response); + } + else if (xhr.status !== 0) { + reject(network_1.ErrorResponse.fromXHR(xhr)); + } + else { + reject(new network_1.NetworkError('No Connection')); + } + } + }; + return xhr; +} + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { + var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); + var ResumingSubscription = (function () { + function ResumingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + this.onTransition = onTransition; + var lastEventId = initialEventId; + logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); + if (lastEventId) { + headers['Last-Event-Id'] = lastEventId; + logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); + } + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpeningSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + this.underlyingSubscription.unsubscribe(); + }; + return OpenSubscriptionState; + }()); + var ResumingSubscriptionState = (function () { + function ResumingSubscriptionState(error, onTransition, lastEventId) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); + var executeSubscriptionOnce = function (error, lastEventId) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = window.setTimeout(function () { + executeNextSubscribeStrategy(lastEventId); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function (lastEventId) { + logger.verbose("ResumingSubscription: trying to re-establish the subscription"); + if (lastEventId) { + logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); + headers['Last-Event-Id'] = lastEventId; + } + _this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { + onTransition(new EndedSubscriptionState(error)); + }, + onError: function (error) { + executeSubscriptionOnce(error, lastEventId); + }, + onEvent: function (event) { + lastEventId = event.eventId; + listeners.onEvent(event); + }, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error, lastEventId); + } + ResumingSubscriptionState.prototype.unsubscribe = function () { + this.onTransition(new EndingSubscriptionState()); + window.clearTimeout(this.timeout); + this.underlyingSubscription.unsubscribe(); + }; + return ResumingSubscriptionState; + }()); + var EndingSubscriptionState = (function () { + function EndingSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); + } + EndingSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription is already ending'); + }; + return EndingSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return ResumingSubscription; + }()); + return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { + var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); + var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); + var RetryingSubscription = (function () { + function RetryingSubscription(listeners, headers) { + var _this = this; + this.unsubscribe = function () { + _this.state.unsubscribe(); + }; + this.onTransition = function (newState) { + _this.state = newState; + }; + var OpeningSubscriptionState = (function () { + function OpeningSubscriptionState(onTransition) { + var _this = this; + logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); + this.underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { + return onTransition(new RetryingSubscriptionState(error, onTransition)); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + } + OpeningSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + throw new Error('Method not implemented.'); + }; + return OpeningSubscriptionState; + }()); + var RetryingSubscriptionState = (function () { + function RetryingSubscriptionState(error, onTransition) { + var _this = this; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); + var executeSubscriptionOnce = function (error) { + listeners.onRetrying(); + var resolveError = function (error) { + if (error instanceof network_1.ErrorResponse) { + error.headers['Request-Method'] = 'SUBSCRIBE'; + } + return retryResolution.attemptRetry(error); + }; + var errorResolution = resolveError(error); + if (errorResolution instanceof retry_strategy_1.Retry) { + _this.timeout = window.setTimeout(function () { + executeNextSubscribeStrategy(); + }, errorResolution.waitTimeMillis); + } + else { + onTransition(new FailedSubscriptionState(error)); + } + }; + var executeNextSubscribeStrategy = function () { + logger.verbose("RetryingSubscription: trying to re-establish the subscription"); + var underlyingSubscription = nextSubscribeStrategy({ + onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, + onError: function (error) { return executeSubscriptionOnce(error); }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); + }, + onRetrying: listeners.onRetrying, + }, headers); + }; + executeSubscriptionOnce(error); + } + RetryingSubscriptionState.prototype.unsubscribe = function () { + window.clearTimeout(this.timeout); + this.onTransition(new EndedSubscriptionState()); + }; + return RetryingSubscriptionState; + }()); + var OpenSubscriptionState = (function () { + function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { + this.underlyingSubscription = underlyingSubscription; + this.onTransition = onTransition; + logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); + listeners.onOpen(headers); + } + OpenSubscriptionState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + this.onTransition(new EndedSubscriptionState()); + }; + return OpenSubscriptionState; + }()); + var EndedSubscriptionState = (function () { + function EndedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); + listeners.onEnd(error); + } + EndedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return EndedSubscriptionState; + }()); + var FailedSubscriptionState = (function () { + function FailedSubscriptionState(error) { + logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); + listeners.onError(error); + } + FailedSubscriptionState.prototype.unsubscribe = function () { + throw new Error('Subscription has already ended'); + }; + return FailedSubscriptionState; + }()); + this.state = new OpeningSubscriptionState(this.onTransition); + } + return RetryingSubscription; + }()); + return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; +}; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { + if (tokenProvider) { + return function (listeners, headers) { + return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); + }; + } + return nextSubscribeStrategy; +}; +var TokenProvidingSubscription = (function () { + function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { + var _this = this; + this.logger = logger; + this.listeners = listeners; + this.headers = headers; + this.tokenProvider = tokenProvider; + this.nextSubscribeStrategy = nextSubscribeStrategy; + this.unsubscribe = function () { + _this.state.unsubscribe(); + _this.state = new InactiveState(_this.logger); + }; + this.state = new ActiveState(logger, headers, nextSubscribeStrategy); + this.subscribe(); + } + TokenProvidingSubscription.prototype.subscribe = function () { + var _this = this; + this.tokenProvider + .fetchToken() + .then(function (token) { + var existingListeners = Object.assign({}, _this.listeners); + _this.state.subscribe(token, { + onEnd: function (error) { + _this.state = new InactiveState(_this.logger); + existingListeners.onEnd(error); + }, + onError: function (error) { + if (_this.isTokenExpiredError(error)) { + _this.tokenProvider.clearToken(token); + _this.subscribe(); + } + else { + _this.state = new InactiveState(_this.logger); + existingListeners.onError(error); + } + }, + onEvent: _this.listeners.onEvent, + onOpen: _this.listeners.onOpen, + }); + }) + .catch(function (error) { + _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); + _this.state = new InactiveState(_this.logger); + _this.listeners.onError(error); + }); + }; + TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { + return (error instanceof network_1.ErrorResponse && + error.statusCode === 401 && + error.info === 'authentication/expired'); + }; + return TokenProvidingSubscription; +}()); +var ActiveState = (function () { + function ActiveState(logger, headers, nextSubscribeStrategy) { + this.logger = logger; + this.headers = headers; + this.nextSubscribeStrategy = nextSubscribeStrategy; + logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); + } + ActiveState.prototype.subscribe = function (token, listeners) { + var _this = this; + this.putTokenIntoHeader(token); + this.underlyingSubscription = this.nextSubscribeStrategy({ + onEnd: function (error) { + _this.logger.verbose("TokenProvidingSubscription: subscription ended"); + listeners.onEnd(error); + }, + onError: function (error) { + _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); + listeners.onError(error); + }, + onEvent: listeners.onEvent, + onOpen: function (headers) { + _this.logger.verbose("TokenProvidingSubscription: subscription opened"); + listeners.onOpen(headers); + }, + onRetrying: listeners.onRetrying, + }, this.headers); + }; + ActiveState.prototype.unsubscribe = function () { + this.underlyingSubscription.unsubscribe(); + }; + ActiveState.prototype.putTokenIntoHeader = function (token) { + this.headers['Authorization'] = "Bearer " + token; + this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); + }; + return ActiveState; +}()); +var InactiveState = (function () { + function InactiveState(logger) { + this.logger = logger; + logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); + } + InactiveState.prototype.subscribe = function (token, listeners) { + this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); + }; + InactiveState.prototype.unsubscribe = function () { + this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); + }; + return InactiveState; +}()); + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createTransportStrategy = function (path, transport, logger) { + return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; +}; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HOST_BASE = 'pusherplatform.io'; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +exports.BaseClient = base_client_1.BaseClient; +var host_base_1 = __webpack_require__(9); +exports.HOST_BASE = host_base_1.HOST_BASE; +var instance_1 = __webpack_require__(15); +exports.Instance = instance_1.default; +var logger_1 = __webpack_require__(1); +exports.ConsoleLogger = logger_1.ConsoleLogger; +exports.EmptyLogger = logger_1.EmptyLogger; +var network_1 = __webpack_require__(0); +exports.ErrorResponse = network_1.ErrorResponse; +exports.NetworkError = network_1.NetworkError; +exports.responseToHeadersObject = network_1.responseToHeadersObject; +exports.XhrReadyState = network_1.XhrReadyState; +var request_1 = __webpack_require__(4); +exports.executeNetworkRequest = request_1.executeNetworkRequest; +exports.sendRawRequest = request_1.sendRawRequest; +var resuming_subscription_1 = __webpack_require__(5); +exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; +var retry_strategy_1 = __webpack_require__(2); +exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; +exports.DoNotRetry = retry_strategy_1.DoNotRetry; +exports.Retry = retry_strategy_1.Retry; +exports.RetryResolution = retry_strategy_1.RetryResolution; +var retrying_subscription_1 = __webpack_require__(6); +exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; +var token_providing_subscription_1 = __webpack_require__(7); +exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; +var transports_1 = __webpack_require__(8); +exports.createTransportStrategy = transports_1.createTransportStrategy; +exports.default = { + BaseClient: base_client_1.BaseClient, + ConsoleLogger: logger_1.ConsoleLogger, + EmptyLogger: logger_1.EmptyLogger, + Instance: instance_1.default, +}; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { + return { + onEnd: subListeners.onEnd, + onError: subListeners.onError, + onEvent: subListeners.onEvent, + onOpen: subListeners.onOpen, + onRetrying: subListeners.onRetrying, + }; +}; + + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.replaceMissingListenersWithNoOps = function (listeners) { + var onEndNoOp = function (error) { }; + var onEnd = listeners.onEnd || onEndNoOp; + var onErrorNoOp = function (error) { }; + var onError = listeners.onError || onErrorNoOp; + var onEventNoOp = function (event) { }; + var onEvent = listeners.onEvent || onEventNoOp; + var onOpenNoOp = function (headers) { }; + var onOpen = listeners.onOpen || onOpenNoOp; + var onRetryingNoOp = function () { }; + var onRetrying = listeners.onRetrying || onRetryingNoOp; + var onSubscribeNoOp = function () { }; + var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; + return { + onEnd: onEnd, + onError: onError, + onEvent: onEvent, + onOpen: onOpen, + onRetrying: onRetrying, + onSubscribe: onSubscribe, + }; +}; + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var HttpTransportState; +(function (HttpTransportState) { + HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; + HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; + HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; + HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; + HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; +})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); +var HttpSubscription = (function () { + function HttpSubscription(xhr, listeners) { + var _this = this; + this.gotEOS = false; + this.lastNewlineIndex = 0; + this.state = HttpTransportState.UNOPENED; + this.xhr = xhr; + this.listeners = listeners; + this.xhr.onreadystatechange = function () { + switch (_this.xhr.readyState) { + case network_1.XhrReadyState.UNSENT: + case network_1.XhrReadyState.OPENED: + case network_1.XhrReadyState.HEADERS_RECEIVED: + _this.assertStateIsIn(HttpTransportState.OPENING); + break; + case network_1.XhrReadyState.LOADING: + _this.onLoading(); + break; + case network_1.XhrReadyState.DONE: + _this.onDone(); + break; + } + }; + this.state = HttpTransportState.OPENING; + this.xhr.send(); + return this; + } + HttpSubscription.prototype.unsubscribe = function () { + this.state = HttpTransportState.ENDED; + this.xhr.abort(); + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + }; + HttpSubscription.prototype.onLoading = function () { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + window.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN); + var err = this.onChunk(); + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + if (err) { + this.state = HttpTransportState.ENDED; + if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else { + } + } + }; + HttpSubscription.prototype.onDone = function () { + if (this.xhr.status === 200) { + if (this.state === HttpTransportState.OPENING) { + this.state = HttpTransportState.OPEN; + if (this.listeners.onOpen) { + this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); + } + } + this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); + var err = this.onChunk(); + if (err) { + this.state = HttpTransportState.ENDED; + if (err.statusCode === 204) { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(err); + } + } + } + else if (this.state <= HttpTransportState.ENDING) { + if (this.listeners.onError) { + this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); + } + } + else { + if (this.listeners.onEnd) { + this.listeners.onEnd(null); + } + } + } + else { + this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); + if (this.state === HttpTransportState.ENDED) { + return; + } + else if (this.xhr.status === 0) { + if (this.listeners.onError) { + this.listeners.onError(new network_1.NetworkError('Connection lost.')); + } + } + else { + if (this.listeners.onError) { + this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); + } + } + } + }; + HttpSubscription.prototype.onChunk = function () { + this.assertStateIsIn(HttpTransportState.OPEN); + var response = this.xhr.responseText; + var newlineIndex = response.lastIndexOf('\n'); + if (newlineIndex > this.lastNewlineIndex) { + var rawEvents = response + .slice(this.lastNewlineIndex, newlineIndex) + .split('\n'); + this.lastNewlineIndex = newlineIndex; + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + if (rawEvent.length === 0) { + continue; + } + var data = JSON.parse(rawEvent); + var err = this.onMessage(data); + if (err != null) { + return err; + } + } + } + }; + HttpSubscription.prototype.assertStateIsIn = function () { + var _this = this; + var validStates = []; + for (var _i = 0; _i < arguments.length; _i++) { + validStates[_i] = arguments[_i]; + } + var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); + if (!stateIsValid) { + var expectedStates = validStates + .map(function (state) { return HttpTransportState[state]; }) + .join(', '); + var actualState = HttpTransportState[this.state]; + window.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); + } + }; + HttpSubscription.prototype.onMessage = function (message) { + this.assertStateIsIn(HttpTransportState.OPEN); + this.verifyMessage(message); + switch (message[0]) { + case 0: + return null; + case 1: + return this.onEventMessage(message); + case 255: + return this.onEOSMessage(message); + default: + return new Error('Unknown Message: ' + JSON.stringify(message)); + } + }; + HttpSubscription.prototype.onEventMessage = function (eventMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eventMessage.length !== 4) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; + if (typeof id !== 'string') { + return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); + } + if (this.listeners.onEvent) { + this.listeners.onEvent({ body: body, headers: headers, eventId: id }); + } + return null; + }; + HttpSubscription.prototype.onEOSMessage = function (eosMessage) { + this.assertStateIsIn(HttpTransportState.OPEN); + if (eosMessage.length !== 4) { + return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); + } + var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; + if (typeof statusCode !== 'number') { + return new Error('Invalid EOS Status Code'); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error('Invalid EOS ElementsHeaders'); + } + this.state = HttpTransportState.ENDING; + return new network_1.ErrorResponse(statusCode, headers, info); + }; + HttpSubscription.prototype.verifyMessage = function (message) { + if (this.gotEOS) { + return new Error('Got another message after EOS message'); + } + if (!Array.isArray(message)) { + return new Error('Message is not an array'); + } + if (message.length < 1) { + return new Error('Message is empty array'); + } + }; + return HttpSubscription; +}()); +var HttpTransport = (function () { + function HttpTransport(host, encrypted) { + if (encrypted === void 0) { encrypted = true; } + this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; + } + HttpTransport.prototype.request = function (requestOptions) { + return this.createXHR(this.baseURL, requestOptions); + }; + HttpTransport.prototype.subscribe = function (path, listeners, headers) { + var requestOptions = { + headers: headers, + method: 'SUBSCRIBE', + path: path, + }; + return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); + }; + HttpTransport.prototype.createXHR = function (baseURL, options) { + var xhr = new window.XMLHttpRequest(); + var path = options.path.replace(/^\/+/, ''); + var endpoint = baseURL + "/" + path; + xhr.open(options.method.toUpperCase(), endpoint, true); + xhr = this.setJSONHeaderIfAppropriate(xhr, options); + if (options.jwt) { + xhr.setRequestHeader('authorization', "Bearer " + options.jwt); + } + if (options.headers) { + for (var key in options.headers) { + if (options.headers.hasOwnProperty(key)) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + } + return xhr; + }; + HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { + if (options.json) { + xhr.setRequestHeader('content-type', 'application/json'); + } + return xhr; + }; + return HttpTransport; +}()); +exports.default = HttpTransport; + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var network_1 = __webpack_require__(0); +var SubscribeMessageType = 100; +var OpenMessageType = 101; +var EventMessageType = 102; +var UnsubscribeMessageType = 198; +var EosMessageType = 199; +var PingMessageType = 16; +var PongMessageType = 17; +var CloseMessageType = 99; +var WSReadyState; +(function (WSReadyState) { + WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; + WSReadyState[WSReadyState["Open"] = 1] = "Open"; + WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; + WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; +})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); +var WsSubscriptions = (function () { + function WsSubscriptions() { + this.subscriptions = {}; + } + WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { + this.subscriptions[subID] = { + headers: headers, + listeners: listeners, + path: path, + }; + return subID; + }; + WsSubscriptions.prototype.has = function (subID) { + return this.subscriptions[subID] !== undefined; + }; + WsSubscriptions.prototype.isEmpty = function () { + return Object.keys(this.subscriptions).length === 0; + }; + WsSubscriptions.prototype.remove = function (subID) { + return delete this.subscriptions[subID]; + }; + WsSubscriptions.prototype.get = function (subID) { + return this.subscriptions[subID]; + }; + WsSubscriptions.prototype.getAll = function () { + return this.subscriptions; + }; + WsSubscriptions.prototype.getAllAsArray = function () { + var _this = this; + return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); + }; + WsSubscriptions.prototype.removeAll = function () { + this.subscriptions = {}; + }; + return WsSubscriptions; +}()); +var WsSubscription = (function () { + function WsSubscription(wsTransport, subID) { + this.wsTransport = wsTransport; + this.subID = subID; + } + WsSubscription.prototype.unsubscribe = function () { + this.wsTransport.unsubscribe(this.subID); + }; + return WsSubscription; +}()); +var pingIntervalMs = 30000; +var pingTimeoutMs = 10000; +var WebSocketTransport = (function () { + function WebSocketTransport(host) { + this.webSocketPath = '/ws'; + this.forcedClose = false; + this.closedError = null; + this.baseURL = "wss://" + host + this.webSocketPath; + this.lastSubscriptionID = 0; + this.subscriptions = new WsSubscriptions(); + this.pendingSubscriptions = new WsSubscriptions(); + this.connect(); + } + WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { + this.tryReconnectIfNeeded(); + var subID = this.lastSubscriptionID++; + if (this.socket.readyState !== WSReadyState.Open) { + this.pendingSubscriptions.add(subID, path, listeners, headers); + return new WsSubscription(this, subID); + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + return new WsSubscription(this, subID); + }; + WebSocketTransport.prototype.unsubscribe = function (subID) { + this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); + var subscription = this.subscriptions.get(subID); + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + this.subscriptions.remove(subID); + }; + WebSocketTransport.prototype.connect = function () { + var _this = this; + this.close(); + this.forcedClose = false; + this.closedError = null; + this.socket = new window.WebSocket(this.baseURL); + this.socket.onopen = function (event) { + var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); + allPendingSubscriptions.forEach(function (subscription) { + var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; + _this.subscribePending(path, listeners, headers, subID); + }); + _this.pendingSubscriptions.removeAll(); + _this.pingInterval = window.setInterval(function () { + if (_this.pongTimeout) { + return; + } + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + return; + } + _this.sendMessage(_this.getMessage(PingMessageType, now)); + _this.lastSentPingID = now; + _this.pongTimeout = window.setTimeout(function () { + var now = new Date().getTime(); + if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { + _this.pongTimeout = null; + return; + } + _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); + }, pingTimeoutMs); + }, pingIntervalMs); + }; + this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; + this.socket.onerror = function (event) { + _this.close(new network_1.NetworkError('Connection was lost.')); + }; + this.socket.onclose = function (event) { + if (!_this.forcedClose) { + _this.tryReconnectIfNeeded(); + return; + } + var callback = _this.closedError + ? function (subscription) { + if (subscription.listeners.onError) { + subscription.listeners.onError(_this.closedError); + } + } + : function (subscription) { + if (subscription.listeners.onEnd) { + subscription.listeners.onEnd(null); + } + }; + var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false + ? _this.pendingSubscriptions + : _this.subscriptions; + allSubscriptions.getAllAsArray().forEach(callback); + allSubscriptions.removeAll(); + if (_this.closedError) { + _this.tryReconnectIfNeeded(); + } + }; + }; + WebSocketTransport.prototype.close = function (error) { + if (!(this.socket instanceof window.WebSocket)) { + return; + } + this.forcedClose = true; + this.closedError = error; + this.socket.close(); + window.clearTimeout(this.pingInterval); + window.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.tryReconnectIfNeeded = function () { + if (this.socket.readyState !== WSReadyState.Closed) { + return; + } + this.connect(); + }; + WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { + if (subID === undefined) { + window.console.logger.debug("Subscription to path " + path + " has an undefined ID"); + return; + } + this.subscriptions.add(subID, path, listeners, headers); + this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); + }; + WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { + return [messageType, id, path, headers]; + }; + WebSocketTransport.prototype.sendMessage = function (message) { + if (this.socket.readyState !== WSReadyState.Open) { + return window.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); + } + this.socket.send(JSON.stringify(message)); + }; + WebSocketTransport.prototype.subscription = function (subID) { + return this.subscriptions.get(subID); + }; + WebSocketTransport.prototype.receiveMessage = function (event) { + this.lastMessageReceivedTimestamp = new Date().getTime(); + var message; + try { + message = JSON.parse(event.data); + } + catch (err) { + this.close(new Error("Message is not valid JSON format. Getting " + event.data)); + return; + } + var nonValidMessageError = this.validateMessage(message); + if (nonValidMessageError) { + this.close(new Error(nonValidMessageError.message)); + return; + } + var messageType = message.shift(); + switch (messageType) { + case PongMessageType: + this.onPongMessage(message); + return; + case PingMessageType: + this.onPingMessage(message); + return; + case CloseMessageType: + this.onCloseMessage(message); + return; + } + var subID = message.shift(); + var subscription = this.subscription(subID); + if (!subscription) { + this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); + return; + } + var listeners = subscription.listeners; + switch (messageType) { + case OpenMessageType: + this.onOpenMessage(message, subID, listeners); + break; + case EventMessageType: + this.onEventMessage(message, listeners); + break; + case EosMessageType: + this.onEOSMessage(message, subID, listeners); + break; + default: + this.close(new Error('Received non existing type of message.')); + } + }; + WebSocketTransport.prototype.validateMessage = function (message) { + if (!Array.isArray(message)) { + return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); + } + if (message.length < 1) { + return new Error("Message is empty array: " + JSON.stringify(message)); + } + return null; + }; + WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { + if (subscriptionListeners.onOpen) { + subscriptionListeners.onOpen(message[1]); + } + }; + WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { + if (eventMessage.length !== 3) { + return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); + } + var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; + if (typeof eventId !== 'string') { + return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); + } + if (subscriptionListeners.onEvent) { + subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); + } + }; + WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { + this.subscriptions.remove(subID); + if (eosMessage.length !== 3) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); + } + return; + } + var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; + if (typeof statusCode !== 'number') { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS Status Code')); + } + return; + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); + } + return; + } + if (statusCode === 204) { + if (subscriptionListeners.onEnd) { + subscriptionListeners.onEnd(null); + } + return; + } + if (subscriptionListeners.onError) { + subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); + } + return; + }; + WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { + var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; + if (typeof statusCode !== 'number') { + return this.close(new Error('Close message: Invalid EOS Status Code')); + } + if (typeof headers !== 'object' || Array.isArray(headers)) { + return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); + } + this.close(); + }; + WebSocketTransport.prototype.onPongMessage = function (message) { + var receviedPongID = message[0]; + if (this.lastSentPingID !== receviedPongID) { + this.close(new network_1.NetworkError("Didn't received pong with proper ID")); + } + window.clearTimeout(this.pongTimeout); + delete this.pongTimeout; + this.lastSentPingID = null; + }; + WebSocketTransport.prototype.onPingMessage = function (message) { + var receviedPingID = message[0]; + this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); + }; + return WebSocketTransport; +}()); +exports.default = WebSocketTransport; + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +Object.defineProperty(exports, "__esModule", { value: true }); +var base_client_1 = __webpack_require__(3); +var host_base_1 = __webpack_require__(9); +var logger_1 = __webpack_require__(1); +var Instance = (function () { + function Instance(options) { + if (!options.locator) { + throw new Error('Expected `locator` property in Instance options!'); + } + var splitInstanceLocator = options.locator.split(':'); + if (splitInstanceLocator.length !== 3) { + throw new Error('The instance locator property is in the wrong format!'); + } + if (!options.serviceName) { + throw new Error('Expected `serviceName` property in Instance options!'); + } + if (!options.serviceVersion) { + throw new Error('Expected `serviceVersion` property in Instance otpions!'); + } + this.platformVersion = splitInstanceLocator[0]; + this.cluster = splitInstanceLocator[1]; + this.id = splitInstanceLocator[2]; + this.serviceName = options.serviceName; + this.serviceVersion = options.serviceVersion; + this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; + this.logger = options.logger || new logger_1.ConsoleLogger(); + this.client = + options.client || + new base_client_1.BaseClient({ + encrypted: options.encrypted, + host: this.host, + logger: this.logger, + }); + this.tokenProvider = options.tokenProvider; + } + Instance.prototype.request = function (options, tokenParams) { + options.path = this.absPath(options.path); + if (options.headers == null || options.headers === undefined) { + options.headers = {}; + } + options.tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.request(options, tokenParams); + }; + Instance.prototype.subscribeNonResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); + }; + Instance.prototype.subscribeResuming = function (options) { + var headers = options.headers || {}; + var retryStrategyOptions = options.retryStrategyOptions || {}; + var tokenProvider = options.tokenProvider || this.tokenProvider; + return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); + }; + Instance.prototype.absPath = function (relativePath) { + return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) + .replace(/\/+/g, '/') + .replace(/\/+$/, ''); + }; + return Instance; +}()); +exports.default = Instance; + + +/***/ }) +/******/ ]); +}); +}); + +unwrapExports(pusherPlatform); +var pusherPlatform_1 = pusherPlatform.BaseClient; +var pusherPlatform_2 = pusherPlatform.HOST_BASE; +var pusherPlatform_3 = pusherPlatform.Instance; +var pusherPlatform_4 = pusherPlatform.sendRawRequest; + +function _isPlaceholder(a) { + return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true; +} + +/** + * Optimized internal one-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry1(fn) { + return function f1(a) { + if (arguments.length === 0 || _isPlaceholder(a)) { + return f1; + } else { + return fn.apply(this, arguments); + } + }; +} + +/** + * Returns a function that always returns the given value. Note that for + * non-primitives the value returned is a reference to the original value. + * + * This function is known as `const`, `constant`, or `K` (for K combinator) in + * other languages and libraries. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig a -> (* -> a) + * @param {*} val The value to wrap in a function + * @return {Function} A Function :: * -> val. + * @example + * + * var t = R.always('Tee'); + * t(); //=> 'Tee' + */ +var always = /*#__PURE__*/_curry1(function always(val) { + return function () { + return val; + }; +}); + +/** + * A function that always returns `false`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig * -> Boolean + * @param {*} + * @return {Boolean} + * @see R.always, R.T + * @example + * + * R.F(); //=> false + */ +var F = /*#__PURE__*/always(false); + +/** + * A function that always returns `true`. Any passed in parameters are ignored. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig * -> Boolean + * @param {*} + * @return {Boolean} + * @see R.always, R.F + * @example + * + * R.T(); //=> true + */ +var T = /*#__PURE__*/always(true); + +/** + * A special placeholder value used to specify "gaps" within curried functions, + * allowing partial application of any combination of arguments, regardless of + * their positions. + * + * If `g` is a curried ternary function and `_` is `R.__`, the following are + * equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2, _)(1, 3)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @constant + * @memberOf R + * @since v0.6.0 + * @category Function + * @example + * + * var greet = R.replace('{name}', R.__, 'Hello, {name}!'); + * greet('Alice'); //=> 'Hello, Alice!' + */ + +/** + * Optimized internal two-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry2(fn) { + return function f2(a, b) { + switch (arguments.length) { + case 0: + return f2; + case 1: + return _isPlaceholder(a) ? f2 : _curry1(function (_b) { + return fn(a, _b); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) { + return fn(_a, b); + }) : _isPlaceholder(b) ? _curry1(function (_b) { + return fn(a, _b); + }) : fn(a, b); + } + }; +} + +/** + * Adds two values. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a + * @param {Number} b + * @return {Number} + * @see R.subtract + * @example + * + * R.add(2, 3); //=> 5 + * R.add(7)(10); //=> 17 + */ +var add = /*#__PURE__*/_curry2(function add(a, b) { + return Number(a) + Number(b); +}); + +/** + * Private `concat` function to merge two array-like objects. + * + * @private + * @param {Array|Arguments} [set1=[]] An array-like object. + * @param {Array|Arguments} [set2=[]] An array-like object. + * @return {Array} A new, merged array. + * @example + * + * _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + */ +function _concat(set1, set2) { + set1 = set1 || []; + set2 = set2 || []; + var idx; + var len1 = set1.length; + var len2 = set2.length; + var result = []; + + idx = 0; + while (idx < len1) { + result[result.length] = set1[idx]; + idx += 1; + } + idx = 0; + while (idx < len2) { + result[result.length] = set2[idx]; + idx += 1; + } + return result; +} + +function _arity(n, fn) { + /* eslint-disable no-unused-vars */ + switch (n) { + case 0: + return function () { + return fn.apply(this, arguments); + }; + case 1: + return function (a0) { + return fn.apply(this, arguments); + }; + case 2: + return function (a0, a1) { + return fn.apply(this, arguments); + }; + case 3: + return function (a0, a1, a2) { + return fn.apply(this, arguments); + }; + case 4: + return function (a0, a1, a2, a3) { + return fn.apply(this, arguments); + }; + case 5: + return function (a0, a1, a2, a3, a4) { + return fn.apply(this, arguments); + }; + case 6: + return function (a0, a1, a2, a3, a4, a5) { + return fn.apply(this, arguments); + }; + case 7: + return function (a0, a1, a2, a3, a4, a5, a6) { + return fn.apply(this, arguments); + }; + case 8: + return function (a0, a1, a2, a3, a4, a5, a6, a7) { + return fn.apply(this, arguments); + }; + case 9: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { + return fn.apply(this, arguments); + }; + case 10: + return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return fn.apply(this, arguments); + }; + default: + throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); + } +} + +/** + * Internal curryN function. + * + * @private + * @category Function + * @param {Number} length The arity of the curried function. + * @param {Array} received An array of arguments received thus far. + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curryN(length, received, fn) { + return function () { + var combined = []; + var argsIdx = 0; + var left = length; + var combinedIdx = 0; + while (combinedIdx < received.length || argsIdx < arguments.length) { + var result; + if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { + result = received[combinedIdx]; + } else { + result = arguments[argsIdx]; + argsIdx += 1; + } + combined[combinedIdx] = result; + if (!_isPlaceholder(result)) { + left -= 1; + } + combinedIdx += 1; + } + return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); + }; +} + +/** + * Returns a curried equivalent of the provided function, with the specified + * arity. The curried function has two unusual capabilities. First, its + * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the + * following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value [`R.__`](#__) may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @since v0.5.0 + * @category Function + * @sig Number -> (* -> a) -> (* -> a) + * @param {Number} length The arity for the returned function. + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curry + * @example + * + * var sumArgs = (...args) => R.sum(args); + * + * var curriedAddFourNumbers = R.curryN(4, sumArgs); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ +var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) { + if (length === 1) { + return _curry1(fn); + } + return _arity(length, _curryN(length, [], fn)); +}); + +/** + * Optimized internal three-arity curry function. + * + * @private + * @category Function + * @param {Function} fn The function to curry. + * @return {Function} The curried function. + */ +function _curry3(fn) { + return function f3(a, b, c) { + switch (arguments.length) { + case 0: + return f3; + case 1: + return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) { + return fn(a, _b, _c); + }); + case 2: + return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) ? _curry2(function (_b, _c) { + return fn(a, _b, _c); + }) : _curry1(function (_c) { + return fn(a, b, _c); + }); + default: + return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) { + return fn(_a, _b, c); + }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) { + return fn(_a, b, _c); + }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) { + return fn(a, _b, _c); + }) : _isPlaceholder(a) ? _curry1(function (_a) { + return fn(_a, b, c); + }) : _isPlaceholder(b) ? _curry1(function (_b) { + return fn(a, _b, c); + }) : _isPlaceholder(c) ? _curry1(function (_c) { + return fn(a, b, _c); + }) : fn(a, b, c); + } + }; +} + +/** + * Tests whether or not an object is an array. + * + * @private + * @param {*} val The object to test. + * @return {Boolean} `true` if `val` is an array, `false` otherwise. + * @example + * + * _isArray([]); //=> true + * _isArray(null); //=> false + * _isArray({}); //=> false + */ +var _isArray = Array.isArray || function _isArray(val) { + return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]'; +}; + +function _isTransformer(obj) { + return typeof obj['@@transducer/step'] === 'function'; +} + +/** + * Returns a function that dispatches with different strategies based on the + * object in list position (last argument). If it is an array, executes [fn]. + * Otherwise, if it has a function with one of the given method names, it will + * execute that function (functor case). Otherwise, if it is a transformer, + * uses transducer [xf] to return a new transformer (transducer case). + * Otherwise, it will default to executing [fn]. + * + * @private + * @param {Array} methodNames properties to check for a custom implementation + * @param {Function} xf transducer to initialize if object is transformer + * @param {Function} fn default ramda implementation + * @return {Function} A function that dispatches on object in list position + */ +function _dispatchable(methodNames, xf, fn) { + return function () { + if (arguments.length === 0) { + return fn(); + } + var args = Array.prototype.slice.call(arguments, 0); + var obj = args.pop(); + if (!_isArray(obj)) { + var idx = 0; + while (idx < methodNames.length) { + if (typeof obj[methodNames[idx]] === 'function') { + return obj[methodNames[idx]].apply(obj, args); + } + idx += 1; + } + if (_isTransformer(obj)) { + var transducer = xf.apply(null, args); + return transducer(obj); + } + } + return fn.apply(this, arguments); + }; +} + +var _xfBase = { + init: function () { + return this.xf['@@transducer/init'](); + }, + result: function (result) { + return this.xf['@@transducer/result'](result); + } +}; + +/** + * Returns the larger of its two arguments. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig Ord a => a -> a -> a + * @param {*} a + * @param {*} b + * @return {*} + * @see R.maxBy, R.min + * @example + * + * R.max(789, 123); //=> 789 + * R.max('a', 'b'); //=> 'b' + */ +var max = /*#__PURE__*/_curry2(function max(a, b) { + return b > a ? b : a; +}); + +function _map(fn, functor) { + var idx = 0; + var len = functor.length; + var result = Array(len); + while (idx < len) { + result[idx] = fn(functor[idx]); + idx += 1; + } + return result; +} + +function _isString(x) { + return Object.prototype.toString.call(x) === '[object String]'; +} + +/** + * Tests whether or not an object is similar to an array. + * + * @private + * @category Type + * @category List + * @sig * -> Boolean + * @param {*} x The object to test. + * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise. + * @example + * + * _isArrayLike([]); //=> true + * _isArrayLike(true); //=> false + * _isArrayLike({}); //=> false + * _isArrayLike({length: 10}); //=> false + * _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true + */ +var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) { + if (_isArray(x)) { + return true; + } + if (!x) { + return false; + } + if (typeof x !== 'object') { + return false; + } + if (_isString(x)) { + return false; + } + if (x.nodeType === 1) { + return !!x.length; + } + if (x.length === 0) { + return true; + } + if (x.length > 0) { + return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); + } + return false; +}); + +var XWrap = /*#__PURE__*/function () { + function XWrap(fn) { + this.f = fn; + } + XWrap.prototype['@@transducer/init'] = function () { + throw new Error('init not implemented on XWrap'); + }; + XWrap.prototype['@@transducer/result'] = function (acc) { + return acc; + }; + XWrap.prototype['@@transducer/step'] = function (acc, x) { + return this.f(acc, x); + }; + + return XWrap; +}(); + +function _xwrap(fn) { + return new XWrap(fn); +} + +/** + * Creates a function that is bound to a context. + * Note: `R.bind` does not provide the additional argument-binding capabilities of + * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). + * + * @func + * @memberOf R + * @since v0.6.0 + * @category Function + * @category Object + * @sig (* -> *) -> {*} -> (* -> *) + * @param {Function} fn The function to bind to context + * @param {Object} thisObj The context to bind `fn` to + * @return {Function} A function that will execute in the context of `thisObj`. + * @see R.partial + * @example + * + * var log = R.bind(console.log, console); + * R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3} + * // logs {a: 2} + * @symb R.bind(f, o)(a, b) = f.call(o, a, b) + */ +var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) { + return _arity(fn.length, function () { + return fn.apply(thisObj, arguments); + }); +}); + +function _arrayReduce(xf, acc, list) { + var idx = 0; + var len = list.length; + while (idx < len) { + acc = xf['@@transducer/step'](acc, list[idx]); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + idx += 1; + } + return xf['@@transducer/result'](acc); +} + +function _iterableReduce(xf, acc, iter) { + var step = iter.next(); + while (!step.done) { + acc = xf['@@transducer/step'](acc, step.value); + if (acc && acc['@@transducer/reduced']) { + acc = acc['@@transducer/value']; + break; + } + step = iter.next(); + } + return xf['@@transducer/result'](acc); +} + +function _methodReduce(xf, acc, obj, methodName) { + return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc)); +} + +var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator'; + +function _reduce(fn, acc, list) { + if (typeof fn === 'function') { + fn = _xwrap(fn); + } + if (_isArrayLike(list)) { + return _arrayReduce(fn, acc, list); + } + if (typeof list['fantasy-land/reduce'] === 'function') { + return _methodReduce(fn, acc, list, 'fantasy-land/reduce'); + } + if (list[symIterator] != null) { + return _iterableReduce(fn, acc, list[symIterator]()); + } + if (typeof list.next === 'function') { + return _iterableReduce(fn, acc, list); + } + if (typeof list.reduce === 'function') { + return _methodReduce(fn, acc, list, 'reduce'); + } + + throw new TypeError('reduce: list must be array or iterable'); +} + +var XMap = /*#__PURE__*/function () { + function XMap(f, xf) { + this.xf = xf; + this.f = f; + } + XMap.prototype['@@transducer/init'] = _xfBase.init; + XMap.prototype['@@transducer/result'] = _xfBase.result; + XMap.prototype['@@transducer/step'] = function (result, input) { + return this.xf['@@transducer/step'](result, this.f(input)); + }; + + return XMap; +}(); + +var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) { + return new XMap(f, xf); +}); + +function _has(prop, obj) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +var toString = Object.prototype.toString; +var _isArguments = function () { + return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) { + return toString.call(x) === '[object Arguments]'; + } : function _isArguments(x) { + return _has('callee', x); + }; +}; + +// cover IE < 9 keys issues +var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString'); +var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; +// Safari bug +var hasArgsEnumBug = /*#__PURE__*/function () { + return arguments.propertyIsEnumerable('length'); +}(); + +var contains = function contains(list, item) { + var idx = 0; + while (idx < list.length) { + if (list[idx] === item) { + return true; + } + idx += 1; + } + return false; +}; + +/** + * Returns a list containing the names of all the enumerable own properties of + * the supplied object. + * Note that the order of the output array is not guaranteed to be consistent + * across different JS platforms. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {k: v} -> [k] + * @param {Object} obj The object to extract properties from + * @return {Array} An array of the object's own properties. + * @see R.keysIn, R.values + * @example + * + * R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c'] + */ +var _keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? function keys(obj) { + return Object(obj) !== obj ? [] : Object.keys(obj); +} : function keys(obj) { + if (Object(obj) !== obj) { + return []; + } + var prop, nIdx; + var ks = []; + var checkArgsLength = hasArgsEnumBug && _isArguments(obj); + for (prop in obj) { + if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) { + ks[ks.length] = prop; + } + } + if (hasEnumBug) { + nIdx = nonEnumerableProps.length - 1; + while (nIdx >= 0) { + prop = nonEnumerableProps[nIdx]; + if (_has(prop, obj) && !contains(ks, prop)) { + ks[ks.length] = prop; + } + nIdx -= 1; + } + } + return ks; +}; +var keys = /*#__PURE__*/_curry1(_keys); + +/** + * Takes a function and + * a [functor](https://github.com/fantasyland/fantasy-land#functor), + * applies the function to each of the functor's values, and returns + * a functor of the same shape. + * + * Ramda provides suitable `map` implementations for `Array` and `Object`, + * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`. + * + * Dispatches to the `map` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * Also treats functions as functors and will compose them together. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Functor f => (a -> b) -> f a -> f b + * @param {Function} fn The function to be called on every element of the input `list`. + * @param {Array} list The list to be iterated over. + * @return {Array} The new list. + * @see R.transduce, R.addIndex + * @example + * + * var double = x => x * 2; + * + * R.map(double, [1, 2, 3]); //=> [2, 4, 6] + * + * R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6} + * @symb R.map(f, [a, b]) = [f(a), f(b)] + * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) } + * @symb R.map(f, functor_o) = functor_o.map(f) + */ +var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) { + switch (Object.prototype.toString.call(functor)) { + case '[object Function]': + return curryN(functor.length, function () { + return fn.call(this, functor.apply(this, arguments)); + }); + case '[object Object]': + return _reduce(function (acc, key) { + acc[key] = fn(functor[key]); + return acc; + }, {}, keys(functor)); + default: + return _map(fn, functor); + } +})); + +/** + * Retrieve the value at a given path. + * + * @func + * @memberOf R + * @since v0.2.0 + * @category Object + * @typedefn Idx = String | Int + * @sig [Idx] -> {a} -> a | Undefined + * @param {Array} path The path to use. + * @param {Object} obj The object to retrieve the nested property from. + * @return {*} The data at `path`. + * @see R.prop + * @example + * + * R.path(['a', 'b'], {a: {b: 2}}); //=> 2 + * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined + */ +var path = /*#__PURE__*/_curry2(function path(paths, obj) { + var val = obj; + var idx = 0; + while (idx < paths.length) { + if (val == null) { + return; + } + val = val[paths[idx]]; + idx += 1; + } + return val; +}); + +/** + * Returns a function that when supplied an object returns the indicated + * property of that object, if it exists. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig s -> {s: a} -> a | Undefined + * @param {String} p The property name + * @param {Object} obj The object to query + * @return {*} The value at `obj.p`. + * @see R.path + * @example + * + * R.prop('x', {x: 100}); //=> 100 + * R.prop('x', {}); //=> undefined + */ + +var prop = /*#__PURE__*/_curry2(function prop(p, obj) { + return path([p], obj); +}); + +/** + * Returns a new list by plucking the same named property off all objects in + * the list supplied. + * + * `pluck` will work on + * any [functor](https://github.com/fantasyland/fantasy-land#functor) in + * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Functor f => k -> f {k: v} -> f v + * @param {Number|String} key The key name to pluck off of each object. + * @param {Array} f The array or functor to consider. + * @return {Array} The list of values for the given key. + * @see R.props + * @example + * + * R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2] + * R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3] + * R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5} + * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5] + * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5] + */ +var pluck = /*#__PURE__*/_curry2(function pluck(p, list) { + return map(prop(p), list); +}); + +/** + * Returns a single item by iterating through the list, successively calling + * the iterator function and passing it an accumulator value and the current + * value from the array, and then passing the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It may use + * [`R.reduced`](#reduced) to shortcut the iteration. + * + * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function + * is *(value, acc)*. + * + * Note: `R.reduce` does not skip deleted or unassigned indices (sparse + * arrays), unlike the native `Array.prototype.reduce` method. For more details + * on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description + * + * Dispatches to the `reduce` method of the third argument, if present. When + * doing so, it is up to the user to handle the [`R.reduced`](#reduced) + * shortcuting, as this is not implemented by `reduce`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig ((a, b) -> a) -> a -> [b] -> a + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. + * @param {*} acc The accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @see R.reduced, R.addIndex, R.reduceRight + * @example + * + * R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10 + * // - -10 + * // / \ / \ + * // - 4 -6 4 + * // / \ / \ + * // - 3 ==> -3 3 + * // / \ / \ + * // - 2 -1 2 + * // / \ / \ + * // 0 1 0 1 + * + * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d) + */ +var reduce = /*#__PURE__*/_curry3(_reduce); + +/** + * ap applies a list of functions to a list of values. + * + * Dispatches to the `ap` method of the second argument, if present. Also + * treats curried functions as applicatives. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category Function + * @sig [a -> b] -> [a] -> [b] + * @sig Apply f => f (a -> b) -> f a -> f b + * @sig (a -> b -> c) -> (a -> b) -> (a -> c) + * @param {*} applyF + * @param {*} applyX + * @return {*} + * @example + * + * R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6] + * R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"] + * + * // R.ap can also be used as S combinator + * // when only two functions are passed + * R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA' + * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)] + */ +var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) { + return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) { + return applyF(x)(applyX(x)); + } : + // else + _reduce(function (acc, f) { + return _concat(acc, map(f, applyX)); + }, [], applyF); +}); + +/** + * Returns a new list containing the contents of the given list, followed by + * the given element. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig a -> [a] -> [a] + * @param {*} el The element to add to the end of the new list. + * @param {Array} list The list of elements to add a new item to. + * list. + * @return {Array} A new list containing the elements of the old list followed by `el`. + * @see R.prepend + * @example + * + * R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests'] + * R.append('tests', []); //=> ['tests'] + * R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']] + */ +var append = /*#__PURE__*/_curry2(function append(el, list) { + return _concat(list, [el]); +}); + +/** + * Returns a list of all the enumerable own properties of the supplied object. + * Note that the order of the output array is not guaranteed across different + * JS platforms. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {k: v} -> [v] + * @param {Object} obj The object to extract values from + * @return {Array} An array of the values of the object's own properties. + * @see R.valuesIn, R.keys + * @example + * + * R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3] + */ +var values = /*#__PURE__*/_curry1(function values(obj) { + var props = keys(obj); + var len = props.length; + var vals = []; + var idx = 0; + while (idx < len) { + vals[idx] = obj[props[idx]]; + idx += 1; + } + return vals; +}); + +/** + * Determine if the passed argument is an integer. + * + * @private + * @param {*} n + * @category Type + * @return {Boolean} + */ + +function _isFunction(x) { + return Object.prototype.toString.call(x) === '[object Function]'; +} + +/** + * "lifts" a function to be the specified arity, so that it may "map over" that + * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). + * + * @func + * @memberOf R + * @since v0.7.0 + * @category Function + * @sig Number -> (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The lifted function. + * @see R.lift, R.ap + * @example + * + * var madd3 = R.liftN(3, (...args) => R.sum(args)); + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + */ +var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) { + var lifted = curryN(arity, fn); + return curryN(arity, function () { + return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1)); + }); +}); + +/** + * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other + * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). + * + * @func + * @memberOf R + * @since v0.7.0 + * @category Function + * @sig (*... -> *) -> ([*]... -> [*]) + * @param {Function} fn The function to lift into higher context + * @return {Function} The lifted function. + * @see R.liftN + * @example + * + * var madd3 = R.lift((a, b, c) => a + b + c); + * + * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] + * + * var madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e); + * + * madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24] + */ +var lift = /*#__PURE__*/_curry1(function lift(fn) { + return liftN(fn.length, fn); +}); + +/** + * Returns a curried equivalent of the provided function. The curried function + * has two unusual capabilities. First, its arguments needn't be provided one + * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the + * following are equivalent: + * + * - `g(1)(2)(3)` + * - `g(1)(2, 3)` + * - `g(1, 2)(3)` + * - `g(1, 2, 3)` + * + * Secondly, the special placeholder value [`R.__`](#__) may be used to specify + * "gaps", allowing partial application of any combination of arguments, + * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), + * the following are equivalent: + * + * - `g(1, 2, 3)` + * - `g(_, 2, 3)(1)` + * - `g(_, _, 3)(1)(2)` + * - `g(_, _, 3)(1, 2)` + * - `g(_, 2)(1)(3)` + * - `g(_, 2)(1, 3)` + * - `g(_, 2)(_, 3)(1)` + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (* -> a) -> (* -> a) + * @param {Function} fn The function to curry. + * @return {Function} A new, curried function. + * @see R.curryN + * @example + * + * var addFourNumbers = (a, b, c, d) => a + b + c + d; + * + * var curriedAddFourNumbers = R.curry(addFourNumbers); + * var f = curriedAddFourNumbers(1, 2); + * var g = f(3); + * g(4); //=> 10 + */ +var curry = /*#__PURE__*/_curry1(function curry(fn) { + return curryN(fn.length, fn); +}); + +/** + * Returns the result of calling its first argument with the remaining + * arguments. This is occasionally useful as a converging function for + * [`R.converge`](#converge): the first branch can produce a function while the + * remaining branches produce values to be passed to that function as its + * arguments. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Function + * @sig (*... -> a),*... -> a + * @param {Function} fn The function to apply to the remaining arguments. + * @param {...*} args Any number of positional arguments. + * @return {*} + * @see R.apply + * @example + * + * R.call(R.add, 1, 2); //=> 3 + * + * var indentN = R.pipe(R.repeat(' '), + * R.join(''), + * R.replace(/^(?!$)/gm)); + * + * var format = R.converge(R.call, [ + * R.pipe(R.prop('indent'), indentN), + * R.prop('value') + * ]); + * + * format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> ' foo\n bar\n baz\n' + * @symb R.call(f, a, b) = f(a, b) + */ +var call = /*#__PURE__*/curry(function call(fn) { + return fn.apply(this, Array.prototype.slice.call(arguments, 1)); +}); + +/** + * `_makeFlat` is a helper function that returns a one-level or fully recursive + * function based on the flag passed in. + * + * @private + */ +function _makeFlat(recursive) { + return function flatt(list) { + var value, jlen, j; + var result = []; + var idx = 0; + var ilen = list.length; + + while (idx < ilen) { + if (_isArrayLike(list[idx])) { + value = recursive ? flatt(list[idx]) : list[idx]; + j = 0; + jlen = value.length; + while (j < jlen) { + result[result.length] = value[j]; + j += 1; + } + } else { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; + }; +} + +function _forceReduced(x) { + return { + '@@transducer/value': x, + '@@transducer/reduced': true + }; +} + +var preservingReduced = function (xf) { + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return xf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + var ret = xf['@@transducer/step'](result, input); + return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret; + } + }; +}; + +var _flatCat = function _xcat(xf) { + var rxf = preservingReduced(xf); + return { + '@@transducer/init': _xfBase.init, + '@@transducer/result': function (result) { + return rxf['@@transducer/result'](result); + }, + '@@transducer/step': function (result, input) { + return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input); + } + }; +}; + +var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) { + return map(f, _flatCat(xf)); +}); + +/** + * `chain` maps a function over a list and concatenates the results. `chain` + * is also known as `flatMap` in some libraries + * + * Dispatches to the `chain` method of the second argument, if present, + * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain). + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig Chain m => (a -> m b) -> m a -> m b + * @param {Function} fn The function to map with + * @param {Array} list The list to map over + * @return {Array} The result of flat-mapping `list` with `fn` + * @example + * + * var duplicate = n => [n, n]; + * R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3] + * + * R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1] + */ +var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { + if (typeof monad === 'function') { + return function (x) { + return fn(monad(x))(x); + }; + } + return _makeFlat(false)(map(fn, monad)); +})); + +function _cloneRegExp(pattern) { + return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : '')); +} + +/** + * Gives a single-word string description of the (native) type of a value, + * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not + * attempt to distinguish user Object types any further, reporting them all as + * 'Object'. + * + * @func + * @memberOf R + * @since v0.8.0 + * @category Type + * @sig (* -> {*}) -> String + * @param {*} val The value to test + * @return {String} + * @example + * + * R.type({}); //=> "Object" + * R.type(1); //=> "Number" + * R.type(false); //=> "Boolean" + * R.type('s'); //=> "String" + * R.type(null); //=> "Null" + * R.type([]); //=> "Array" + * R.type(/[A-z]/); //=> "RegExp" + * R.type(() => {}); //=> "Function" + * R.type(undefined); //=> "Undefined" + */ +var type = /*#__PURE__*/_curry1(function type(val) { + return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1); +}); + +/** + * Copies an object. + * + * @private + * @param {*} value The value to be copied + * @param {Array} refFrom Array containing the source references + * @param {Array} refTo Array containing the copied source references + * @param {Boolean} deep Whether or not to perform deep cloning. + * @return {*} The copied value. + */ +function _clone(value, refFrom, refTo, deep) { + var copy = function copy(copiedValue) { + var len = refFrom.length; + var idx = 0; + while (idx < len) { + if (value === refFrom[idx]) { + return refTo[idx]; + } + idx += 1; + } + refFrom[idx + 1] = value; + refTo[idx + 1] = copiedValue; + for (var key in value) { + copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key]; + } + return copiedValue; + }; + switch (type(value)) { + case 'Object': + return copy({}); + case 'Array': + return copy([]); + case 'Date': + return new Date(value.valueOf()); + case 'RegExp': + return _cloneRegExp(value); + default: + return value; + } +} + +/** + * Creates a deep copy of the value which may contain (nested) `Array`s and + * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are + * assigned by reference rather than copied + * + * Dispatches to a `clone` method if present. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig {*} -> {*} + * @param {*} value The object or array to clone + * @return {*} A deeply cloned copy of `val` + * @example + * + * var objects = [{}, {}, {}]; + * var objectsClone = R.clone(objects); + * objects === objectsClone; //=> false + * objects[0] === objectsClone[0]; //=> false + */ +var clone = /*#__PURE__*/_curry1(function clone(value) { + return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true); +}); + +/** + * A function that returns the `!` of its argument. It will return `true` when + * passed false-y value, and `false` when passed a truth-y one. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Logic + * @sig * -> Boolean + * @param {*} a any value + * @return {Boolean} the logical inverse of passed argument. + * @see R.complement + * @example + * + * R.not(true); //=> false + * R.not(false); //=> true + * R.not(0); //=> true + * R.not(1); //=> false + */ +var not = /*#__PURE__*/_curry1(function not(a) { + return !a; +}); + +/** + * Takes a function `f` and returns a function `g` such that if called with the same arguments + * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`. + * + * `R.complement` may be applied to any functor + * + * @func + * @memberOf R + * @since v0.12.0 + * @category Logic + * @sig (*... -> *) -> (*... -> Boolean) + * @param {Function} f + * @return {Function} + * @see R.not + * @example + * + * var isNotNil = R.complement(R.isNil); + * isNil(null); //=> true + * isNotNil(null); //=> false + * isNil(7); //=> false + * isNotNil(7); //=> true + */ +var complement = /*#__PURE__*/lift(not); + +function _pipe(f, g) { + return function () { + return g.call(this, f.apply(this, arguments)); + }; +} + +/** + * This checks whether a function has a [methodname] function. If it isn't an + * array it will execute that function otherwise it will default to the ramda + * implementation. + * + * @private + * @param {Function} fn ramda implemtation + * @param {String} methodname property to check for a custom implementation + * @return {Object} Whatever the return value of the method is. + */ +function _checkForMethod(methodname, fn) { + return function () { + var length = arguments.length; + if (length === 0) { + return fn(); + } + var obj = arguments[length - 1]; + return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1)); + }; +} + +/** + * Returns the elements of the given list or string (or object with a `slice` + * method) from `fromIndex` (inclusive) to `toIndex` (exclusive). + * + * Dispatches to the `slice` method of the third argument, if present. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig Number -> Number -> [a] -> [a] + * @sig Number -> Number -> String -> String + * @param {Number} fromIndex The start index (inclusive). + * @param {Number} toIndex The end index (exclusive). + * @param {*} list + * @return {*} + * @example + * + * R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd'] + * R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c'] + * R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] + * R.slice(0, 3, 'ramda'); //=> 'ram' + */ +var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) { + return Array.prototype.slice.call(list, fromIndex, toIndex); +})); + +/** + * Returns all but the first element of the given list or string (or object + * with a `tail` method). + * + * Dispatches to the `slice` method of the first argument, if present. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.head, R.init, R.last + * @example + * + * R.tail([1, 2, 3]); //=> [2, 3] + * R.tail([1, 2]); //=> [2] + * R.tail([1]); //=> [] + * R.tail([]); //=> [] + * + * R.tail('abc'); //=> 'bc' + * R.tail('ab'); //=> 'b' + * R.tail('a'); //=> '' + * R.tail(''); //=> '' + */ +var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity))); + +/** + * Performs left-to-right function composition. The leftmost function may have + * any arity; the remaining functions must be unary. + * + * In some libraries this function is named `sequence`. + * + * **Note:** The result of pipe is not automatically curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z) + * @param {...Function} functions + * @return {Function} + * @see R.compose + * @example + * + * var f = R.pipe(Math.pow, R.negate, R.inc); + * + * f(3, 4); // -(3^4) + 1 + * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b))) + */ +function pipe() { + if (arguments.length === 0) { + throw new Error('pipe requires at least one argument'); + } + return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments))); +} + +/** + * Returns a new list or string with the elements or characters in reverse + * order. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {Array|String} list + * @return {Array|String} + * @example + * + * R.reverse([1, 2, 3]); //=> [3, 2, 1] + * R.reverse([1, 2]); //=> [2, 1] + * R.reverse([1]); //=> [1] + * R.reverse([]); //=> [] + * + * R.reverse('abc'); //=> 'cba' + * R.reverse('ab'); //=> 'ba' + * R.reverse('a'); //=> 'a' + * R.reverse(''); //=> '' + */ +var reverse = /*#__PURE__*/_curry1(function reverse(list) { + return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse(); +}); + +/** + * Performs right-to-left function composition. The rightmost function may have + * any arity; the remaining functions must be unary. + * + * **Note:** The result of compose is not automatically curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z) + * @param {...Function} ...functions The functions to compose + * @return {Function} + * @see R.pipe + * @example + * + * var classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName + * var yellGreeting = R.compose(R.toUpper, classyGreeting); + * yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND" + * + * R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7 + * + * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b))) + */ +function compose() { + if (arguments.length === 0) { + throw new Error('compose requires at least one argument'); + } + return pipe.apply(this, reverse(arguments)); +} + +function _arrayFromIterator(iter) { + var list = []; + var next; + while (!(next = iter.next()).done) { + list.push(next.value); + } + return list; +} + +function _containsWith(pred, x, list) { + var idx = 0; + var len = list.length; + + while (idx < len) { + if (pred(x, list[idx])) { + return true; + } + idx += 1; + } + return false; +} + +function _functionName(f) { + // String(x => x) evaluates to "x => x", so the pattern may not match. + var match = String(f).match(/^function (\w*)/); + return match == null ? '' : match[1]; +} + +/** + * Returns true if its arguments are identical, false otherwise. Values are + * identical if they reference the same memory. `NaN` is identical to `NaN`; + * `0` and `-0` are not identical. + * + * @func + * @memberOf R + * @since v0.15.0 + * @category Relation + * @sig a -> a -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * var o = {}; + * R.identical(o, o); //=> true + * R.identical(1, 1); //=> true + * R.identical(1, '1'); //=> false + * R.identical([], []); //=> false + * R.identical(0, -0); //=> false + * R.identical(NaN, NaN); //=> true + */ +var identical = /*#__PURE__*/_curry2(function identical(a, b) { + // SameValue algorithm + if (a === b) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + return a !== 0 || 1 / a === 1 / b; + } else { + // Step 6.a: NaN == NaN + return a !== a && b !== b; + } +}); + +/** + * private _uniqContentEquals function. + * That function is checking equality of 2 iterator contents with 2 assumptions + * - iterators lengths are the same + * - iterators values are unique + * + * false-positive result will be returned for comparision of, e.g. + * - [1,2,3] and [1,2,3,4] + * - [1,1,1] and [1,2,3] + * */ + +function _uniqContentEquals(aIterator, bIterator, stackA, stackB) { + var a = _arrayFromIterator(aIterator); + var b = _arrayFromIterator(bIterator); + + function eq(_a, _b) { + return _equals(_a, _b, stackA.slice(), stackB.slice()); + } + + // if *a* array contains any element that is not included in *b* + return !_containsWith(function (b, aItem) { + return !_containsWith(eq, aItem, b); + }, b, a); +} + +function _equals(a, b, stackA, stackB) { + if (identical(a, b)) { + return true; + } + + var typeA = type(a); + + if (typeA !== type(b)) { + return false; + } + + if (a == null || b == null) { + return false; + } + + if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') { + return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a); + } + + if (typeof a.equals === 'function' || typeof b.equals === 'function') { + return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a); + } + + switch (typeA) { + case 'Arguments': + case 'Array': + case 'Object': + if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') { + return a === b; + } + break; + case 'Boolean': + case 'Number': + case 'String': + if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf()))) { + return false; + } + break; + case 'Date': + if (!identical(a.valueOf(), b.valueOf())) { + return false; + } + break; + case 'Error': + return a.name === b.name && a.message === b.message; + case 'RegExp': + if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) { + return false; + } + break; + } + + var idx = stackA.length - 1; + while (idx >= 0) { + if (stackA[idx] === a) { + return stackB[idx] === b; + } + idx -= 1; + } + + switch (typeA) { + case 'Map': + if (a.size !== b.size) { + return false; + } + + return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b])); + case 'Set': + if (a.size !== b.size) { + return false; + } + + return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b])); + case 'Arguments': + case 'Array': + case 'Object': + case 'Boolean': + case 'Number': + case 'String': + case 'Date': + case 'Error': + case 'RegExp': + case 'Int8Array': + case 'Uint8Array': + case 'Uint8ClampedArray': + case 'Int16Array': + case 'Uint16Array': + case 'Int32Array': + case 'Uint32Array': + case 'Float32Array': + case 'Float64Array': + case 'ArrayBuffer': + break; + default: + // Values of other types are only equal if identical. + return false; + } + + var keysA = keys(a); + if (keysA.length !== keys(b).length) { + return false; + } + + var extendedStackA = stackA.concat([a]); + var extendedStackB = stackB.concat([b]); + + idx = keysA.length - 1; + while (idx >= 0) { + var key = keysA[idx]; + if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) { + return false; + } + idx -= 1; + } + return true; +} + +/** + * Returns `true` if its arguments are equivalent, `false` otherwise. Handles + * cyclical data structures. + * + * Dispatches symmetrically to the `equals` methods of both arguments, if + * present. + * + * @func + * @memberOf R + * @since v0.15.0 + * @category Relation + * @sig a -> b -> Boolean + * @param {*} a + * @param {*} b + * @return {Boolean} + * @example + * + * R.equals(1, 1); //=> true + * R.equals(1, '1'); //=> false + * R.equals([1, 2, 3], [1, 2, 3]); //=> true + * + * var a = {}; a.v = a; + * var b = {}; b.v = b; + * R.equals(a, b); //=> true + */ +var equals = /*#__PURE__*/_curry2(function equals(a, b) { + return _equals(a, b, [], []); +}); + +function _indexOf(list, a, idx) { + var inf, item; + // Array.prototype.indexOf doesn't exist below IE9 + if (typeof list.indexOf === 'function') { + switch (typeof a) { + case 'number': + if (a === 0) { + // manually crawl the list to distinguish between +0 and -0 + inf = 1 / a; + while (idx < list.length) { + item = list[idx]; + if (item === 0 && 1 / item === inf) { + return idx; + } + idx += 1; + } + return -1; + } else if (a !== a) { + // NaN + while (idx < list.length) { + item = list[idx]; + if (typeof item === 'number' && item !== item) { + return idx; + } + idx += 1; + } + return -1; + } + // non-zero numbers can utilise Set + return list.indexOf(a, idx); + + // all these types can utilise Set + case 'string': + case 'boolean': + case 'function': + case 'undefined': + return list.indexOf(a, idx); + + case 'object': + if (a === null) { + // null can utilise Set + return list.indexOf(a, idx); + } + } + } + // anything else not covered above, defer to R.equals + while (idx < list.length) { + if (equals(list[idx], a)) { + return idx; + } + idx += 1; + } + return -1; +} + +function _contains(a, list) { + return _indexOf(list, a, 0) >= 0; +} + +function _quote(s) { + var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace + .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0'); + + return '"' + escaped.replace(/"/g, '\\"') + '"'; +} + +/** + * Polyfill from . + */ +var pad = function pad(n) { + return (n < 10 ? '0' : '') + n; +}; + +var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) { + return d.toISOString(); +} : function _toISOString(d) { + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'; +}; + +function _complement(f) { + return function () { + return !f.apply(this, arguments); + }; +} + +function _filter(fn, list) { + var idx = 0; + var len = list.length; + var result = []; + + while (idx < len) { + if (fn(list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + return result; +} + +function _isObject(x) { + return Object.prototype.toString.call(x) === '[object Object]'; +} + +var XFilter = /*#__PURE__*/function () { + function XFilter(f, xf) { + this.xf = xf; + this.f = f; + } + XFilter.prototype['@@transducer/init'] = _xfBase.init; + XFilter.prototype['@@transducer/result'] = _xfBase.result; + XFilter.prototype['@@transducer/step'] = function (result, input) { + return this.f(input) ? this.xf['@@transducer/step'](result, input) : result; + }; + + return XFilter; +}(); + +var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) { + return new XFilter(f, xf); +}); + +/** + * Takes a predicate and a `Filterable`, and returns a new filterable of the + * same type containing the members of the given filterable which satisfy the + * given predicate. Filterable objects include plain objects or any object + * that has a filter method such as `Array`. + * + * Dispatches to the `filter` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> f a + * @param {Function} pred + * @param {Array} filterable + * @return {Array} Filterable + * @see R.reject, R.transduce, R.addIndex + * @example + * + * var isEven = n => n % 2 === 0; + * + * R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4] + * + * R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} + */ +var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) { + return _isObject(filterable) ? _reduce(function (acc, key) { + if (pred(filterable[key])) { + acc[key] = filterable[key]; + } + return acc; + }, {}, keys(filterable)) : + // else + _filter(pred, filterable); +})); + +/** + * The complement of [`filter`](#filter). + * + * Acts as a transducer if a transformer is given in list position. Filterable + * objects include plain objects or any object that has a filter method such + * as `Array`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> f a + * @param {Function} pred + * @param {Array} filterable + * @return {Array} + * @see R.filter, R.transduce, R.addIndex + * @example + * + * var isOdd = (n) => n % 2 === 1; + * + * R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4] + * + * R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} + */ +var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) { + return filter(_complement(pred), filterable); +}); + +function _toString(x, seen) { + var recur = function recur(y) { + var xs = seen.concat([x]); + return _contains(y, xs) ? '' : _toString(y, xs); + }; + + // mapPairs :: (Object, [String]) -> [String] + var mapPairs = function (obj, keys$$1) { + return _map(function (k) { + return _quote(k) + ': ' + recur(obj[k]); + }, keys$$1.slice().sort()); + }; + + switch (Object.prototype.toString.call(x)) { + case '[object Arguments]': + return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))'; + case '[object Array]': + return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) { + return (/^\d+$/.test(k) + ); + }, keys(x)))).join(', ') + ']'; + case '[object Boolean]': + return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString(); + case '[object Date]': + return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')'; + case '[object Null]': + return 'null'; + case '[object Number]': + return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10); + case '[object String]': + return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x); + case '[object Undefined]': + return 'undefined'; + default: + if (typeof x.toString === 'function') { + var repr = x.toString(); + if (repr !== '[object Object]') { + return repr; + } + } + return '{' + mapPairs(x, keys(x)).join(', ') + '}'; + } +} + +/** + * Returns the string representation of the given value. `eval`'ing the output + * should result in a value equivalent to the input value. Many of the built-in + * `toString` methods do not satisfy this requirement. + * + * If the given value is an `[object Object]` with a `toString` method other + * than `Object.prototype.toString`, this method is invoked with no arguments + * to produce the return value. This means user-defined constructor functions + * can provide a suitable `toString` method. For example: + * + * function Point(x, y) { + * this.x = x; + * this.y = y; + * } + * + * Point.prototype.toString = function() { + * return 'new Point(' + this.x + ', ' + this.y + ')'; + * }; + * + * R.toString(new Point(1, 2)); //=> 'new Point(1, 2)' + * + * @func + * @memberOf R + * @since v0.14.0 + * @category String + * @sig * -> String + * @param {*} val + * @return {String} + * @example + * + * R.toString(42); //=> '42' + * R.toString('abc'); //=> '"abc"' + * R.toString([1, 2, 3]); //=> '[1, 2, 3]' + * R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}' + * R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")' + */ +var toString$1 = /*#__PURE__*/_curry1(function toString(val) { + return _toString(val, []); +}); + +/** + * Returns the result of concatenating the given lists or strings. + * + * Note: `R.concat` expects both arguments to be of the same type, + * unlike the native `Array.prototype.concat` method. It will throw + * an error if you `concat` an Array with a non-Array value. + * + * Dispatches to the `concat` method of the first argument, if present. + * Can also concatenate two members of a [fantasy-land + * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup). + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] -> [a] + * @sig String -> String -> String + * @param {Array|String} firstList The first list + * @param {Array|String} secondList The second list + * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of + * `secondList`. + * + * @example + * + * R.concat('ABC', 'DEF'); // 'ABCDEF' + * R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] + * R.concat([], []); //=> [] + */ +var concat = /*#__PURE__*/_curry2(function concat(a, b) { + if (_isArray(a)) { + if (_isArray(b)) { + return a.concat(b); + } + throw new TypeError(toString$1(b) + ' is not an array'); + } + if (_isString(a)) { + if (_isString(b)) { + return a + b; + } + throw new TypeError(toString$1(b) + ' is not a string'); + } + if (a != null && _isFunction(a['fantasy-land/concat'])) { + return a['fantasy-land/concat'](b); + } + if (a != null && _isFunction(a.concat)) { + return a.concat(b); + } + throw new TypeError(toString$1(a) + ' does not have a method named "concat" or "fantasy-land/concat"'); +}); + +/** + * Returns `true` if the specified value is equal, in [`R.equals`](#equals) + * terms, to at least one element of the given list; `false` otherwise. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig a -> [a] -> Boolean + * @param {Object} a The item to compare against. + * @param {Array} list The array to consider. + * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise. + * @see R.any + * @example + * + * R.contains(3, [1, 2, 3]); //=> true + * R.contains(4, [1, 2, 3]); //=> false + * R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true + * R.contains([42], [[42]]); //=> true + */ +var contains$1 = /*#__PURE__*/_curry2(_contains); + +/** + * Accepts a converging function and a list of branching functions and returns + * a new function. When invoked, this new function is applied to some + * arguments, each branching function is applied to those same arguments. The + * results of each branching function are passed as arguments to the converging + * function to produce the return value. + * + * @func + * @memberOf R + * @since v0.4.2 + * @category Function + * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z) + * @param {Function} after A function. `after` will be invoked with the return values of + * `fn1` and `fn2` as its arguments. + * @param {Array} functions A list of functions. + * @return {Function} A new function. + * @see R.useWith + * @example + * + * var average = R.converge(R.divide, [R.sum, R.length]) + * average([1, 2, 3, 4, 5, 6, 7]) //=> 4 + * + * var strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower]) + * strangeConcat("Yodel") //=> "YODELyodel" + * + * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b)) + */ +var converge = /*#__PURE__*/_curry2(function converge(after, fns) { + return curryN(reduce(max, 0, pluck('length', fns)), function () { + var args = arguments; + var context = this; + return after.apply(context, _map(function (fn) { + return fn.apply(context, args); + }, fns)); + }); +}); + +var XReduceBy = /*#__PURE__*/function () { + function XReduceBy(valueFn, valueAcc, keyFn, xf) { + this.valueFn = valueFn; + this.valueAcc = valueAcc; + this.keyFn = keyFn; + this.xf = xf; + this.inputs = {}; + } + XReduceBy.prototype['@@transducer/init'] = _xfBase.init; + XReduceBy.prototype['@@transducer/result'] = function (result) { + var key; + for (key in this.inputs) { + if (_has(key, this.inputs)) { + result = this.xf['@@transducer/step'](result, this.inputs[key]); + if (result['@@transducer/reduced']) { + result = result['@@transducer/value']; + break; + } + } + } + this.inputs = null; + return this.xf['@@transducer/result'](result); + }; + XReduceBy.prototype['@@transducer/step'] = function (result, input) { + var key = this.keyFn(input); + this.inputs[key] = this.inputs[key] || [key, this.valueAcc]; + this.inputs[key][1] = this.valueFn(this.inputs[key][1], input); + return result; + }; + + return XReduceBy; +}(); + +var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) { + return new XReduceBy(valueFn, valueAcc, keyFn, xf); +}); + +/** + * Groups the elements of the list according to the result of calling + * the String-returning function `keyFn` on each element and reduces the elements + * of each group to a single value via the reducer function `valueFn`. + * + * This function is basically a more general [`groupBy`](#groupBy) function. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.20.0 + * @category List + * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a} + * @param {Function} valueFn The function that reduces the elements of each group to a single + * value. Receives two values, accumulator for a particular group and the current element. + * @param {*} acc The (initial) accumulator value for each group. + * @param {Function} keyFn The function that maps the list's element into a key. + * @param {Array} list The array to group. + * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of + * `valueFn` for elements which produced that key when passed to `keyFn`. + * @see R.groupBy, R.reduce + * @example + * + * var reduceToNamesBy = R.reduceBy((acc, student) => acc.concat(student.name), []); + * var namesByGrade = reduceToNamesBy(function(student) { + * var score = student.score; + * return score < 65 ? 'F' : + * score < 70 ? 'D' : + * score < 80 ? 'C' : + * score < 90 ? 'B' : 'A'; + * }); + * var students = [{name: 'Lucy', score: 92}, + * {name: 'Drew', score: 85}, + * // ... + * {name: 'Bart', score: 62}]; + * namesByGrade(students); + * // { + * // 'A': ['Lucy'], + * // 'B': ['Drew'] + * // // ..., + * // 'F': ['Bart'] + * // } + */ +var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) { + return _reduce(function (acc, elt) { + var key = keyFn(elt); + acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt); + return acc; + }, {}, list); +})); + +/** + * Counts the elements of a list according to how many match each value of a + * key generated by the supplied function. Returns an object mapping the keys + * produced by `fn` to the number of occurrences in the list. Note that all + * keys are coerced to strings because of how JavaScript objects work. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig (a -> String) -> [a] -> {*} + * @param {Function} fn The function used to map values to keys. + * @param {Array} list The list to count elements from. + * @return {Object} An object mapping keys to number of occurrences in the list. + * @example + * + * var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2]; + * R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1} + * + * var letters = ['a', 'b', 'A', 'a', 'B', 'c']; + * R.countBy(R.toLower)(letters); //=> {'a': 3, 'b': 2, 'c': 1} + */ +var countBy = /*#__PURE__*/reduceBy(function (acc, elem) { + return acc + 1; +}, 0); + +/** + * Decrements its argument. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} n - 1 + * @see R.inc + * @example + * + * R.dec(42); //=> 41 + */ +var dec = /*#__PURE__*/add(-1); + +/** + * Finds the set (i.e. no duplicates) of all elements in the first list not + * contained in the second list. Objects and Arrays are compared in terms of + * value equality, not reference equality. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig [*] -> [*] -> [*] + * @param {Array} list1 The first list. + * @param {Array} list2 The second list. + * @return {Array} The elements in `list1` that are not in `list2`. + * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without + * @example + * + * R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2] + * R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5] + * R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}] + */ +var difference = /*#__PURE__*/_curry2(function difference(first, second) { + var out = []; + var idx = 0; + var firstLen = first.length; + while (idx < firstLen) { + if (!_contains(first[idx], second) && !_contains(first[idx], out)) { + out[out.length] = first[idx]; + } + idx += 1; + } + return out; +}); + +var XDropRepeatsWith = /*#__PURE__*/function () { + function XDropRepeatsWith(pred, xf) { + this.xf = xf; + this.pred = pred; + this.lastValue = undefined; + this.seenFirstValue = false; + } + + XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init; + XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result; + XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) { + var sameAsLast = false; + if (!this.seenFirstValue) { + this.seenFirstValue = true; + } else if (this.pred(this.lastValue, input)) { + sameAsLast = true; + } + this.lastValue = input; + return sameAsLast ? result : this.xf['@@transducer/step'](result, input); + }; + + return XDropRepeatsWith; +}(); + +var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) { + return new XDropRepeatsWith(pred, xf); +}); + +/** + * Returns the nth element of the given list or string. If n is negative the + * element at index length + n is returned. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig Number -> [a] -> a | Undefined + * @sig Number -> String -> String + * @param {Number} offset + * @param {*} list + * @return {*} + * @example + * + * var list = ['foo', 'bar', 'baz', 'quux']; + * R.nth(1, list); //=> 'bar' + * R.nth(-1, list); //=> 'quux' + * R.nth(-99, list); //=> undefined + * + * R.nth(2, 'abc'); //=> 'c' + * R.nth(3, 'abc'); //=> '' + * @symb R.nth(-1, [a, b, c]) = c + * @symb R.nth(0, [a, b, c]) = a + * @symb R.nth(1, [a, b, c]) = b + */ +var nth = /*#__PURE__*/_curry2(function nth(offset, list) { + var idx = offset < 0 ? list.length + offset : offset; + return _isString(list) ? list.charAt(idx) : list[idx]; +}); + +/** + * Returns the last element of the given list or string. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.init, R.head, R.tail + * @example + * + * R.last(['fi', 'fo', 'fum']); //=> 'fum' + * R.last([]); //=> undefined + * + * R.last('abc'); //=> 'c' + * R.last(''); //=> '' + */ +var last = /*#__PURE__*/nth(-1); + +/** + * Returns a new list without any consecutively repeating elements. Equality is + * determined by applying the supplied predicate to each pair of consecutive elements. The + * first element in a series of equal elements will be preserved. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.14.0 + * @category List + * @sig ((a, a) -> Boolean) -> [a] -> [a] + * @param {Function} pred A predicate used to test whether two items are equal. + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @see R.transduce + * @example + * + * var l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3]; + * R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3] + */ +var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) { + var result = []; + var idx = 1; + var len = list.length; + if (len !== 0) { + result[0] = list[0]; + while (idx < len) { + if (!pred(last(result), list[idx])) { + result[result.length] = list[idx]; + } + idx += 1; + } + } + return result; +})); + +/** + * Returns a new list without any consecutively repeating elements. + * [`R.equals`](#equals) is used to determine equality. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.14.0 + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} `list` without repeating elements. + * @see R.transduce + * @example + * + * R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2] + */ +var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals))); + +/** + * Returns the empty value of its argument's type. Ramda defines the empty + * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other + * types are supported if they define `.empty`, + * `.prototype.empty` or implement the + * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid). + * + * Dispatches to the `empty` method of the first argument, if present. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category Function + * @sig a -> a + * @param {*} x + * @return {*} + * @example + * + * R.empty(Just(42)); //=> Nothing() + * R.empty([1, 2, 3]); //=> [] + * R.empty('unicorns'); //=> '' + * R.empty({x: 1, y: 2}); //=> {} + */ +var empty = /*#__PURE__*/_curry1(function empty(x) { + return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () { + return arguments; + }() : + // else + void 0; +}); + +/** + * Returns a new function much like the supplied one, except that the first two + * arguments' order is reversed. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z) + * @param {Function} fn The function to invoke with its first two parameters reversed. + * @return {*} The result of invoking `fn` with its first two parameters' order reversed. + * @example + * + * var mergeThree = (a, b, c) => [].concat(a, b, c); + * + * mergeThree(1, 2, 3); //=> [1, 2, 3] + * + * R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3] + * @symb R.flip(f)(a, b, c) = f(b, a, c) + */ +var flip = /*#__PURE__*/_curry1(function flip(fn) { + return curryN(fn.length, function (a, b) { + var args = Array.prototype.slice.call(arguments, 0); + args[0] = b; + args[1] = a; + return fn.apply(this, args); + }); +}); + +/** + * Iterate over an input `list`, calling a provided function `fn` for each + * element in the list. + * + * `fn` receives one argument: *(value)*. + * + * Note: `R.forEach` does not skip deleted or unassigned indices (sparse + * arrays), unlike the native `Array.prototype.forEach` method. For more + * details on this behavior, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description + * + * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns + * the original array. In some libraries this function is named `each`. + * + * Dispatches to the `forEach` method of the second argument, if present. + * + * @func + * @memberOf R + * @since v0.1.1 + * @category List + * @sig (a -> *) -> [a] -> [a] + * @param {Function} fn The function to invoke. Receives one argument, `value`. + * @param {Array} list The list to iterate over. + * @return {Array} The original list. + * @see R.addIndex + * @example + * + * var printXPlusFive = x => console.log(x + 5); + * R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3] + * // logs 6 + * // logs 7 + * // logs 8 + * @symb R.forEach(f, [a, b, c]) = [a, b, c] + */ +var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) { + var len = list.length; + var idx = 0; + while (idx < len) { + fn(list[idx]); + idx += 1; + } + return list; +})); + +/** + * Iterate over an input `object`, calling a provided function `fn` for each + * key and value in the object. + * + * `fn` receives three argument: *(value, key, obj)*. + * + * @func + * @memberOf R + * @since v0.23.0 + * @category Object + * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a + * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`. + * @param {Object} obj The object to iterate over. + * @return {Object} The original object. + * @example + * + * var printKeyConcatValue = (value, key) => console.log(key + ':' + value); + * R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2} + * // logs x:1 + * // logs y:2 + * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b} + */ +var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) { + var keyList = keys(obj); + var idx = 0; + while (idx < keyList.length) { + var key = keyList[idx]; + fn(obj[key], key, obj); + idx += 1; + } + return obj; +}); + +/** + * Creates a new object from a list key-value pairs. If a key appears in + * multiple pairs, the rightmost pair is included in the object. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig [[k,v]] -> {k: v} + * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object. + * @return {Object} The object made by pairing up `keys` and `values`. + * @see R.toPairs, R.pair + * @example + * + * R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3} + */ +var fromPairs = /*#__PURE__*/_curry1(function fromPairs(pairs) { + var result = {}; + var idx = 0; + while (idx < pairs.length) { + result[pairs[idx][0]] = pairs[idx][1]; + idx += 1; + } + return result; +}); + +/** + * Splits a list into sub-lists stored in an object, based on the result of + * calling a String-returning function on each element, and grouping the + * results according to values returned. + * + * Dispatches to the `groupBy` method of the second argument, if present. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig (a -> String) -> [a] -> {String: [a]} + * @param {Function} fn Function :: a -> String + * @param {Array} list The array to group + * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements + * that produced that key when passed to `fn`. + * @see R.transduce + * @example + * + * var byGrade = R.groupBy(function(student) { + * var score = student.score; + * return score < 65 ? 'F' : + * score < 70 ? 'D' : + * score < 80 ? 'C' : + * score < 90 ? 'B' : 'A'; + * }); + * var students = [{name: 'Abby', score: 84}, + * {name: 'Eddy', score: 58}, + * // ... + * {name: 'Jack', score: 69}]; + * byGrade(students); + * // { + * // 'A': [{name: 'Dianne', score: 99}], + * // 'B': [{name: 'Abby', score: 84}] + * // // ..., + * // 'F': [{name: 'Eddy', score: 58}] + * // } + */ +var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) { + if (acc == null) { + acc = []; + } + acc.push(item); + return acc; +}, null))); + +/** + * Returns the first element of the given list or string. In some libraries + * this function is named `first`. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> a | Undefined + * @sig String -> String + * @param {Array|String} list + * @return {*} + * @see R.tail, R.init, R.last + * @example + * + * R.head(['fi', 'fo', 'fum']); //=> 'fi' + * R.head([]); //=> undefined + * + * R.head('abc'); //=> 'a' + * R.head(''); //=> '' + */ +var head = /*#__PURE__*/nth(0); + +function _identity(x) { + return x; +} + +/** + * A function that does nothing but return the parameter supplied to it. Good + * as a default or placeholder function. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig a -> a + * @param {*} x The value to return. + * @return {*} The input value, `x`. + * @example + * + * R.identity(1); //=> 1 + * + * var obj = {}; + * R.identity(obj) === obj; //=> true + * @symb R.identity(a) = a + */ +var identity = /*#__PURE__*/_curry1(_identity); + +/** + * Increments its argument. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category Math + * @sig Number -> Number + * @param {Number} n + * @return {Number} n + 1 + * @see R.dec + * @example + * + * R.inc(42); //=> 43 + */ +var inc = /*#__PURE__*/add(1); + +/** + * Given a function that generates a key, turns a list of objects into an + * object indexing the objects by the given key. Note that if multiple + * objects generate the same value for the indexing key only the last value + * will be included in the generated object. + * + * Acts as a transducer if a transformer is given in list position. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category List + * @sig (a -> String) -> [{k: v}] -> {k: {k: v}} + * @param {Function} fn Function :: a -> String + * @param {Array} array The array of objects to index + * @return {Object} An object indexing each array element by the given property. + * @example + * + * var list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}]; + * R.indexBy(R.prop('id'), list); + * //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}} + */ +var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) { + return elem; +}, null); + +/** + * Returns all but the last element of the given list or string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category List + * @sig [a] -> [a] + * @sig String -> String + * @param {*} list + * @return {*} + * @see R.last, R.head, R.tail + * @example + * + * R.init([1, 2, 3]); //=> [1, 2] + * R.init([1, 2]); //=> [1] + * R.init([1]); //=> [] + * R.init([]); //=> [] + * + * R.init('abc'); //=> 'ab' + * R.init('ab'); //=> 'a' + * R.init('a'); //=> '' + * R.init(''); //=> '' + */ +var init = /*#__PURE__*/slice(0, -1); + +var _Set = /*#__PURE__*/function () { + function _Set() { + /* globals Set */ + this._nativeSet = typeof Set === 'function' ? new Set() : null; + this._items = {}; + } + + // until we figure out why jsdoc chokes on this + // @param item The item to add to the Set + // @returns {boolean} true if the item did not exist prior, otherwise false + // + _Set.prototype.add = function (item) { + return !hasOrAdd(item, true, this); + }; + + // + // @param item The item to check for existence in the Set + // @returns {boolean} true if the item exists in the Set, otherwise false + // + _Set.prototype.has = function (item) { + return hasOrAdd(item, false, this); + }; + + // + // Combines the logic for checking whether an item is a member of the set and + // for adding a new item to the set. + // + // @param item The item to check or add to the Set instance. + // @param shouldAdd If true, the item will be added to the set if it doesn't + // already exist. + // @param set The set instance to check or add to. + // @return {boolean} true if the item already existed, otherwise false. + // + return _Set; +}(); + +function hasOrAdd(item, shouldAdd, set) { + var type = typeof item; + var prevSize, newSize; + switch (type) { + case 'string': + case 'number': + // distinguish between +0 and -0 + if (item === 0 && 1 / item === -Infinity) { + if (set._items['-0']) { + return true; + } else { + if (shouldAdd) { + set._items['-0'] = true; + } + return false; + } + } + // these types can all utilise the native Set + if (set._nativeSet !== null) { + if (shouldAdd) { + prevSize = set._nativeSet.size; + set._nativeSet.add(item); + newSize = set._nativeSet.size; + return newSize === prevSize; + } else { + return set._nativeSet.has(item); + } + } else { + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = {}; + set._items[type][item] = true; + } + return false; + } else if (item in set._items[type]) { + return true; + } else { + if (shouldAdd) { + set._items[type][item] = true; + } + return false; + } + } + + case 'boolean': + // set._items['boolean'] holds a two element array + // representing [ falseExists, trueExists ] + if (type in set._items) { + var bIdx = item ? 1 : 0; + if (set._items[type][bIdx]) { + return true; + } else { + if (shouldAdd) { + set._items[type][bIdx] = true; + } + return false; + } + } else { + if (shouldAdd) { + set._items[type] = item ? [false, true] : [true, false]; + } + return false; + } + + case 'function': + // compare functions for reference equality + if (set._nativeSet !== null) { + if (shouldAdd) { + prevSize = set._nativeSet.size; + set._nativeSet.add(item); + newSize = set._nativeSet.size; + return newSize === prevSize; + } else { + return set._nativeSet.has(item); + } + } else { + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = [item]; + } + return false; + } + if (!_contains(item, set._items[type])) { + if (shouldAdd) { + set._items[type].push(item); + } + return false; + } + return true; + } + + case 'undefined': + if (set._items[type]) { + return true; + } else { + if (shouldAdd) { + set._items[type] = true; + } + return false; + } + + case 'object': + if (item === null) { + if (!set._items['null']) { + if (shouldAdd) { + set._items['null'] = true; + } + return false; + } + return true; + } + /* falls through */ + default: + // reduce the search size of heterogeneous sets by creating buckets + // for each type. + type = Object.prototype.toString.call(item); + if (!(type in set._items)) { + if (shouldAdd) { + set._items[type] = [item]; + } + return false; + } + // scan through all previously applied items + if (!_contains(item, set._items[type])) { + if (shouldAdd) { + set._items[type].push(item); + } + return false; + } + return true; + } +} + +/** + * Returns a new list containing only one copy of each element in the original + * list, based upon the value returned by applying the supplied function to + * each list element. Prefers the first item if the supplied function produces + * the same value on two items. [`R.equals`](#equals) is used for comparison. + * + * @func + * @memberOf R + * @since v0.16.0 + * @category List + * @sig (a -> b) -> [a] -> [a] + * @param {Function} fn A function used to produce a value to use during comparisons. + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10] + */ +var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) { + var set = new _Set(); + var result = []; + var idx = 0; + var appliedItem, item; + + while (idx < list.length) { + item = list[idx]; + appliedItem = fn(item); + if (set.add(appliedItem)) { + result.push(item); + } + idx += 1; + } + return result; +}); + +/** + * Returns a new list containing only one copy of each element in the original + * list. [`R.equals`](#equals) is used to determine equality. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig [a] -> [a] + * @param {Array} list The array to consider. + * @return {Array} The list of unique items. + * @example + * + * R.uniq([1, 1, 2, 1]); //=> [1, 2] + * R.uniq([1, '1']); //=> [1, '1'] + * R.uniq([[42], [42]]); //=> [[42]] + */ +var uniq = /*#__PURE__*/uniqBy(identity); + +/** + * Turns a named method with a specified arity into a function that can be + * called directly supplied with arguments and a target object. + * + * The returned function is curried and accepts `arity + 1` parameters where + * the final parameter is the target object. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *) + * @param {Number} arity Number of arguments the returned function should take + * before the target object. + * @param {String} method Name of the method to call. + * @return {Function} A new curried function. + * @see R.construct + * @example + * + * var sliceFrom = R.invoker(1, 'slice'); + * sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm' + * var sliceFrom6 = R.invoker(2, 'slice')(6); + * sliceFrom6(8, 'abcdefghijklm'); //=> 'gh' + * @symb R.invoker(0, 'method')(o) = o['method']() + * @symb R.invoker(1, 'method')(a, o) = o['method'](a) + * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b) + */ +var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) { + return curryN(arity + 1, function () { + var target = arguments[arity]; + if (target != null && _isFunction(target[method])) { + return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity)); + } + throw new TypeError(toString$1(target) + ' does not have a method named "' + method + '"'); + }); +}); + +/** + * Returns `true` if the given value is its type's empty value; `false` + * otherwise. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Logic + * @sig a -> Boolean + * @param {*} x + * @return {Boolean} + * @see R.empty + * @example + * + * R.isEmpty([1, 2, 3]); //=> false + * R.isEmpty([]); //=> true + * R.isEmpty(''); //=> true + * R.isEmpty(null); //=> false + * R.isEmpty({}); //=> true + * R.isEmpty({length: 0}); //=> false + */ +var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) { + return x != null && equals(x, empty(x)); +}); + +/** + * Returns a string made by inserting the `separator` between each element and + * concatenating all the elements into a single string. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig String -> [a] -> String + * @param {Number|String} separator The string used to separate the elements. + * @param {Array} xs The elements to join into a string. + * @return {String} str The string made by concatenating `xs` with `separator`. + * @see R.split + * @example + * + * var spacer = R.join(' '); + * spacer(['a', 2, 3.4]); //=> 'a 2 3.4' + * R.join('|', [1, 2, 3]); //=> '1|2|3' + */ +var join = /*#__PURE__*/invoker(1, 'join'); + +/** + * juxt applies a list of functions to a list of values. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Function + * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n]) + * @param {Array} fns An array of functions + * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters. + * @see R.applySpec + * @example + * + * var getRange = R.juxt([Math.min, Math.max]); + * getRange(3, 4, 9, -3); //=> [-3, 9] + * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)] + */ +var juxt = /*#__PURE__*/_curry1(function juxt(fns) { + return converge(function () { + return Array.prototype.slice.call(arguments, 0); + }, fns); +}); + +function _isNumber(x) { + return Object.prototype.toString.call(x) === '[object Number]'; +} + +/** + * Returns the number of elements in the array by returning `list.length`. + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig [a] -> Number + * @param {Array} list The array to inspect. + * @return {Number} The length of the array. + * @example + * + * R.length([]); //=> 0 + * R.length([1, 2, 3]); //=> 3 + */ +var length = /*#__PURE__*/_curry1(function length(list) { + return list != null && _isNumber(list.length) ? list.length : NaN; +}); + +/** + * Adds together all the elements of a list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The sum of all the numbers in the list. + * @see R.reduce + * @example + * + * R.sum([2,4,6,8,100,1]); //=> 121 + */ +var sum = /*#__PURE__*/reduce(add, 0); + +/** + * A customisable version of [`R.memoize`](#memoize). `memoizeWith` takes an + * additional function that will be applied to a given argument set and used to + * create the cache key under which the results of the function to be memoized + * will be stored. Care must be taken when implementing key generation to avoid + * clashes that may overwrite previous entries erroneously. + * + * + * @func + * @memberOf R + * @since v0.24.0 + * @category Function + * @sig (*... -> String) -> (*... -> a) -> (*... -> a) + * @param {Function} fn The function to generate the cache key. + * @param {Function} fn The function to memoize. + * @return {Function} Memoized version of `fn`. + * @see R.memoize + * @example + * + * let count = 0; + * const factorial = R.memoizeWith(R.identity, n => { + * count += 1; + * return R.product(R.range(1, n + 1)); + * }); + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * count; //=> 1 + */ +var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) { + var cache = {}; + return _arity(fn.length, function () { + var key = mFn.apply(this, arguments); + if (!_has(key, cache)) { + cache[key] = fn.apply(this, arguments); + } + return cache[key]; + }); +}); + +/** + * Creates a new function that, when invoked, caches the result of calling `fn` + * for a given argument set and returns the result. Subsequent calls to the + * memoized `fn` with the same argument set will not result in an additional + * call to `fn`; instead, the cached result for that set of arguments will be + * returned. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig (*... -> a) -> (*... -> a) + * @param {Function} fn The function to memoize. + * @return {Function} Memoized version of `fn`. + * @see R.memoizeWith + * @deprecated since v0.25.0 + * @example + * + * let count = 0; + * const factorial = R.memoize(n => { + * count += 1; + * return R.product(R.range(1, n + 1)); + * }); + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * factorial(5); //=> 120 + * count; //=> 1 + */ +var memoize = /*#__PURE__*/memoizeWith(function () { + return toString$1(arguments); +}); + +/** + * Creates a new object with the own properties of the two provided objects. If + * a key exists in both objects, the provided function is applied to the key + * and the values associated with the key in each object, with the result being + * used as the value associated with the key in the returned object. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Object + * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a} + * @param {Function} fn + * @param {Object} l + * @param {Object} r + * @return {Object} + * @see R.mergeDeepWithKey, R.merge, R.mergeWith + * @example + * + * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r + * R.mergeWithKey(concatValues, + * { a: true, thing: 'foo', values: [10, 20] }, + * { b: true, thing: 'bar', values: [15, 35] }); + * //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] } + * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 } + */ +var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) { + var result = {}; + var k; + + for (k in l) { + if (_has(k, l)) { + result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k]; + } + } + + for (k in r) { + if (_has(k, r) && !_has(k, result)) { + result[k] = r[k]; + } + } + + return result; +}); + +/** + * Creates a new object with the own properties of the two provided objects. If + * a key exists in both objects, the provided function is applied to the values + * associated with the key in each object, with the result being used as the + * value associated with the key in the returned object. + * + * @func + * @memberOf R + * @since v0.19.0 + * @category Object + * @sig ((a, a) -> a) -> {a} -> {a} -> {a} + * @param {Function} fn + * @param {Object} l + * @param {Object} r + * @return {Object} + * @see R.mergeDeepWith, R.merge, R.mergeWithKey + * @example + * + * R.mergeWith(R.concat, + * { a: true, values: [10, 20] }, + * { b: true, values: [15, 35] }); + * //=> { a: true, b: true, values: [10, 20, 15, 35] } + */ +var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) { + return mergeWithKey(function (_, _l, _r) { + return fn(_l, _r); + }, l, r); +}); + +/** + * Multiplies two numbers. Equivalent to `a * b` but curried. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig Number -> Number -> Number + * @param {Number} a The first value. + * @param {Number} b The second value. + * @return {Number} The result of `a * b`. + * @see R.divide + * @example + * + * var double = R.multiply(2); + * var triple = R.multiply(3); + * double(3); //=> 6 + * triple(4); //=> 12 + * R.multiply(2, 5); //=> 10 + */ +var multiply = /*#__PURE__*/_curry2(function multiply(a, b) { + return a * b; +}); + +function _createPartialApplicator(concat) { + return _curry2(function (fn, args) { + return _arity(Math.max(0, fn.length - args.length), function () { + return fn.apply(this, concat(args, arguments)); + }); + }); +} + +/** + * Takes a function `f` and a list of arguments, and returns a function `g`. + * When applied, `g` returns the result of applying `f` to the arguments + * provided to `g` followed by the arguments provided initially. + * + * @func + * @memberOf R + * @since v0.10.0 + * @category Function + * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x) + * @param {Function} f + * @param {Array} args + * @return {Function} + * @see R.partial + * @example + * + * var greet = (salutation, title, firstName, lastName) => + * salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; + * + * var greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']); + * + * greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!' + * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b) + */ +var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat)); + +/** + * Takes a predicate and a list or other `Filterable` object and returns the + * pair of filterable objects of the same type of elements which do and do not + * satisfy, the predicate, respectively. Filterable objects include plain objects or any object + * that has a filter method such as `Array`. + * + * @func + * @memberOf R + * @since v0.1.4 + * @category List + * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a] + * @param {Function} pred A predicate to determine which side the element belongs to. + * @param {Array} filterable the list (or other filterable) to partition. + * @return {Array} An array, containing first the subset of elements that satisfy the + * predicate, and second the subset of elements that do not satisfy. + * @see R.filter, R.reject + * @example + * + * R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); + * // => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] + * + * R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' }); + * // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ] + */ +var partition = /*#__PURE__*/juxt([filter, reject]); + +/** + * Similar to `pick` except that this one includes a `key: undefined` pair for + * properties that don't exist. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @sig [k] -> {k: v} -> {k: v} + * @param {Array} names an array of String property names to copy onto a new object + * @param {Object} obj The object to copy from + * @return {Object} A new object with only properties from `names` on it. + * @see R.pick + * @example + * + * R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} + * R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined} + */ +var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) { + var result = {}; + var idx = 0; + var len = names.length; + while (idx < len) { + var name = names[idx]; + result[name] = obj[name]; + idx += 1; + } + return result; +}); + +/** + * Multiplies together all the elements of a list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Math + * @sig [Number] -> Number + * @param {Array} list An array of numbers + * @return {Number} The product of all the numbers in the list. + * @see R.reduce + * @example + * + * R.product([2,4,6,8,100,1]); //=> 38400 + */ +var product = /*#__PURE__*/reduce(multiply, 1); + +/** + * Accepts a function `fn` and a list of transformer functions and returns a + * new curried function. When the new function is invoked, it calls the + * function `fn` with parameters consisting of the result of calling each + * supplied handler on successive arguments to the new function. + * + * If more arguments are passed to the returned function than transformer + * functions, those arguments are passed directly to `fn` as additional + * parameters. If you expect additional arguments that don't need to be + * transformed, although you can ignore them, it's best to pass an identity + * function so that the new function reports the correct arity. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Function + * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z) + * @param {Function} fn The function to wrap. + * @param {Array} transformers A list of transformer functions + * @return {Function} The wrapped function. + * @see R.converge + * @example + * + * R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81 + * R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81 + * R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32 + * R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32 + * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b)) + */ +var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) { + return curryN(transformers.length, function () { + var args = []; + var idx = 0; + while (idx < transformers.length) { + args.push(transformers[idx].call(this, arguments[idx])); + idx += 1; + } + return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length))); + }); +}); + +/** + * Reasonable analog to SQL `select` statement. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Object + * @category Relation + * @sig [k] -> [{k: v}] -> [{k: v}] + * @param {Array} props The property names to project + * @param {Array} objs The objects to query + * @return {Array} An array of objects with just the `props` properties. + * @example + * + * var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}; + * var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}; + * var kids = [abby, fred]; + * R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}] + */ +var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity + +/** + * Returns a copy of the list, sorted according to the comparator function, + * which should accept two values at a time and return a negative number if the + * first value is smaller, a positive number if it's larger, and zero if they + * are equal. Please note that this is a **copy** of the list. It does not + * modify the original. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category List + * @sig ((a, a) -> Number) -> [a] -> [a] + * @param {Function} comparator A sorting function :: a -> b -> Int + * @param {Array} list The list to sort + * @return {Array} a new array with its elements sorted by the comparator function. + * @example + * + * var diff = function(a, b) { return a - b; }; + * R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7] + */ +var sort = /*#__PURE__*/_curry2(function sort(comparator, list) { + return Array.prototype.slice.call(list, 0).sort(comparator); +}); + +/** + * Splits a string into an array of strings based on the given + * separator. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category String + * @sig (String | RegExp) -> String -> [String] + * @param {String|RegExp} sep The pattern. + * @param {String} str The string to separate into an array. + * @return {Array} The array of strings from `str` separated by `str`. + * @see R.join + * @example + * + * var pathComponents = R.split('/'); + * R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node'] + * + * R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd'] + */ +var split = /*#__PURE__*/invoker(1, 'split'); + +/** + * The lower case version of a string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category String + * @sig String -> String + * @param {String} str The string to lower case. + * @return {String} The lower case version of `str`. + * @see R.toUpper + * @example + * + * R.toLower('XYZ'); //=> 'xyz' + */ +var toLower = /*#__PURE__*/invoker(0, 'toLowerCase'); + +/** + * Converts an object into an array of key, value arrays. Only the object's + * own properties are used. + * Note that the order of the output array is not guaranteed to be consistent + * across different JS platforms. + * + * @func + * @memberOf R + * @since v0.4.0 + * @category Object + * @sig {String: *} -> [[String,*]] + * @param {Object} obj The object to extract from + * @return {Array} An array of key, value arrays from the object's own properties. + * @see R.fromPairs + * @example + * + * R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]] + */ +var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) { + var pairs = []; + for (var prop in obj) { + if (_has(prop, obj)) { + pairs[pairs.length] = [prop, obj[prop]]; + } + } + return pairs; +}); + +/** + * The upper case version of a string. + * + * @func + * @memberOf R + * @since v0.9.0 + * @category String + * @sig String -> String + * @param {String} str The string to upper case. + * @return {String} The upper case version of `str`. + * @see R.toLower + * @example + * + * R.toUpper('abc'); //=> 'ABC' + */ +var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase'); + +/** + * Initializes a transducer using supplied iterator function. Returns a single + * item by iterating through the list, successively calling the transformed + * iterator function and passing it an accumulator value and the current value + * from the array, and then passing the result to the next call. + * + * The iterator function receives two values: *(acc, value)*. It will be + * wrapped as a transformer to initialize the transducer. A transformer can be + * passed directly in place of an iterator function. In both cases, iteration + * may be stopped early with the [`R.reduced`](#reduced) function. + * + * A transducer is a function that accepts a transformer and returns a + * transformer and can be composed directly. + * + * A transformer is an an object that provides a 2-arity reducing iterator + * function, step, 0-arity initial value function, init, and 1-arity result + * extraction function, result. The step function is used as the iterator + * function in reduce. The result function is used to convert the final + * accumulator into the return type and in most cases is + * [`R.identity`](#identity). The init function can be used to provide an + * initial accumulator, but is ignored by transduce. + * + * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer. + * + * @func + * @memberOf R + * @since v0.12.0 + * @category List + * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a + * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. + * @param {Function} fn The iterator function. Receives two values, the accumulator and the + * current element from the array. Wrapped as transformer, if necessary, and used to + * initialize the transducer + * @param {*} acc The initial accumulator value. + * @param {Array} list The list to iterate over. + * @return {*} The final, accumulated value. + * @see R.reduce, R.reduced, R.into + * @example + * + * var numbers = [1, 2, 3, 4]; + * var transducer = R.compose(R.map(R.add(1)), R.take(2)); + * R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3] + * + * var isOdd = (x) => x % 2 === 1; + * var firstOddTransducer = R.compose(R.filter(isOdd), R.take(1)); + * R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1] + */ +var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) { + return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list); +}); + +var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; +var zeroWidth = '\u200b'; +var hasProtoTrim = typeof String.prototype.trim === 'function'; +/** + * Removes (strips) whitespace from both ends of the string. + * + * @func + * @memberOf R + * @since v0.6.0 + * @category String + * @sig String -> String + * @param {String} str The string to trim. + * @return {String} Trimmed version of `str`. + * @example + * + * R.trim(' xyz '); //=> 'xyz' + * R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z'] + */ +var _trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? function trim(str) { + var beginRx = new RegExp('^[' + ws + '][' + ws + ']*'); + var endRx = new RegExp('[' + ws + '][' + ws + ']*$'); + return str.replace(beginRx, '').replace(endRx, ''); +} : function trim(str) { + return str.trim(); +}; + +/** + * Combines two lists into a set (i.e. no duplicates) composed of the elements + * of each list. + * + * @func + * @memberOf R + * @since v0.1.0 + * @category Relation + * @sig [*] -> [*] -> [*] + * @param {Array} as The first list. + * @param {Array} bs The second list. + * @return {Array} The first and second lists concatenated, with + * duplicates removed. + * @example + * + * R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4] + */ +var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat)); + +/** + * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from + * any [Chain](https://github.com/fantasyland/fantasy-land#chain). + * + * @func + * @memberOf R + * @since v0.3.0 + * @category List + * @sig Chain c => c (c a) -> c a + * @param {*} list + * @return {*} + * @see R.flatten, R.chain + * @example + * + * R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]] + * R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6] + */ +var unnest = /*#__PURE__*/chain(_identity); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + + + + + + + + + + + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); + + + + + +var defineProperty = function (obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; +}; + +var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + + + + + + + + + + + + + +var objectWithoutProperties = function (obj, keys) { + var target = {}; + + for (var i in obj) { + if (keys.indexOf(i) >= 0) continue; + if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; + target[i] = obj[i]; + } + + return target; +}; + + + + + + + +var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +}(); + +// urlEncode :: Object -> String +var urlEncode = pipe(filter(function (x) { + return x !== undefined; +}), toPairs, map(function (_ref) { + var _ref2 = slicedToArray(_ref, 2), + k = _ref2[0], + v = _ref2[1]; + + return k + '=' + encodeURIComponent(v); +}), join('&')); + +// appendQueryParam :: String -> String -> String -> String +var appendQueryParam = function appendQueryParam(key, value, url) { + var separator = contains$1('?', url) ? '&' : '?'; + return url + separator + urlEncode(defineProperty({}, key, value)); +}; + +var extractQueryParams = function extractQueryParams(url) { + return contains$1('?', url) ? queryStringToObj(split('?', url)[1]) : {}; +}; + +var queryStringToObj = pipe(split('&'), map(split('=')), fromPairs); + +var typeCheck = function typeCheck(name, expectedType, value) { + var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); + if (type !== expectedType) { + throw new TypeError('expected ' + name + ' to be of type ' + expectedType + ' but was of type ' + type); + } +}; + +// checks that all of an arrays elements are of the given type +var typeCheckArr = function typeCheckArr(name, expectedType, arr) { + if (!Array.isArray(arr)) { + throw new TypeError('expected ' + name + ' to be an array'); + } + arr.forEach(function (value, i) { + return typeCheck(name + '[' + i + ']', expectedType, value); + }); +}; + +// checks that all of an objects values are of the given type +var typeCheckObj = function typeCheckObj(name, expectedType, obj) { + typeCheck(name, 'object', obj); + forEachObjIndexed(function (value, key) { + return typeCheck(key, expectedType, value); + }, obj); +}; + +var checkOneOf = function checkOneOf(name, values, value) { + if (!contains$1(value, values)) { + throw new TypeError('expected ' + name + ' to be one of ' + values + ' but was ' + value); + } +}; + +var unixSeconds = function unixSeconds() { + return Math.floor(Date.now() / 1000); +}; + +// pointfree debugging + +var TokenProvider = +// TODO authContext +function TokenProvider() { + var _this = this; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + url = _ref.url; + + classCallCheck(this, TokenProvider); + + this.fetchToken = function () { + return !_this.cacheIsStale() ? Promise.resolve(_this.cachedToken) : _this.fetchFreshToken().then(function (_ref2) { + var token = _ref2.token, + expiresIn = _ref2.expiresIn; + + _this.cache(token, expiresIn); + return token; + }); + }; + + this.fetchFreshToken = function () { + return pusherPlatform_4({ + method: 'POST', + url: appendQueryParam('user_id', _this.userId, _this.url), + body: urlEncode({ grant_type: 'client_credentials' }), + headers: { + 'content-type': 'application/x-www-form-urlencoded' + } + }).then(function (res) { + var _JSON$parse = JSON.parse(res), + token = _JSON$parse.access_token, + expiresIn = _JSON$parse.expires_in; + + return { token: token, expiresIn: expiresIn }; + }); + }; + + this.cacheIsStale = function () { + return !_this.cachedToken || unixSeconds() > _this.cacheExpiresAt; + }; + + this.cache = function (token, expiresIn) { + _this.cachedToken = token; + _this.cacheExpiresAt = unixSeconds() + expiresIn; + }; + + this.clearCache = function () { + _this.cachedToken = undefined; + _this.cacheExpiresAt = undefined; + }; + + this.setUserId = function (userId) { + _this.clearCache(); + _this.userId = userId; + }; + + typeCheck('url', 'string', url); + this.url = url; +}; + +var Store = function Store() { + var _this = this; + + classCallCheck(this, Store); + this.pendingSets = []; + this.pendingGets = []; + + this.initialize = function (initialStore) { + _this.store = clone(initialStore); + forEach(function (_ref) { + var key = _ref.key, + value = _ref.value, + resolve = _ref.resolve; + + resolve(_this.store[key] = value); + }, _this.pendingSets); + forEach(function (_ref2) { + var key = _ref2.key, + resolve = _ref2.resolve; + + resolve(_this.store[key]); + }, _this.pendingGets); + }; + + this.set = function (key, value) { + if (_this.store) { + return Promise.resolve(_this.store[key] = value); + } else { + return new Promise(function (resolve) { + _this.pendingSets.push({ key: key, value: value, resolve: resolve }); + }); + } + }; + + this.get = function (key) { + if (_this.store) { + return Promise.resolve(_this.store[key]); + } else { + return new Promise(function (resolve) { + _this.pendingGets.push({ key: key, resolve: resolve }); + }); + } + }; + + this.pop = function (key) { + return _this.get(key).then(function (value) { + delete _this.store[key]; + return value; + }); + }; + + this.snapshot = function () { + return _this.store || {}; + }; + + this.getSync = function (key) { + return _this.store ? _this.store[key] : undefined; + }; +}; + +var parseBasicRoom = function parseBasicRoom(data) { + return { + createdAt: data.created_at, + createdByUserId: data.created_by_id, + deletedAt: data.deletedAt, + id: data.id, + isPrivate: data.private, + name: data.name, + updatedAt: data.updated_at, + userIds: data.member_user_ids + }; +}; + +var parseUser = function parseUser(data) { + return { + avatarURL: data.avatar_url, + createdAt: data.created_at, + customData: data.custom_data, + id: data.id, + name: data.name, + updatedAt: data.updated_at + }; +}; + +var parsePresence = function parsePresence(data) { + return { + lastSeenAt: data.last_seen_at, + state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', + userId: data.user_id + }; +}; + +var parseBasicMessage = function parseBasicMessage(data) { + return { + id: data.id, + senderId: data.user_id, + roomId: data.room_id, + text: data.text, + createdAt: data.created_at, + updatedAt: data.updated_at, + attachment: data.attachment && parseAttachment(data.attachment) + }; +}; + +var parseAttachment = function parseAttachment(data) { + return { + link: data.resource_link, + type: data.type, + fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' + }; +}; + +var UserStore = function UserStore(_ref) { + var _this = this; + + var instance = _ref.instance, + presenceStore = _ref.presenceStore, + logger = _ref.logger; + classCallCheck(this, UserStore); + this.store = new Store(); + this.initialize = this.store.initialize; + this.set = this.store.set; + + this.get = function (userId) { + return Promise.all([_this.store.get(userId).then(function (user) { + return user || _this.fetchBasicUser(userId); + }), _this.presenceStore.get(userId)]).then(function (_ref2) { + var _ref3 = slicedToArray(_ref2, 2), + user = _ref3[0], + presence = _ref3[1]; + + return _extends({}, user, { presence: presence }); + }); + }; + + this.fetchBasicUser = function (userId) { + return _this.instance.request({ + method: 'GET', + path: '/users/' + encodeURIComponent(userId) + }).then(function (res) { + var user = parseUser(JSON.parse(res)); + _this.set(userId, user); + return user; + }).catch(function (err) { + _this.logger.warn('error fetching user information:', err); + throw err; + }); + }; + + this.fetchMissingUsers = function (userIds) { + var missing = difference(userIds, map(prop('id'), values(_this.store.snapshot()))); + if (length(missing) === 0) { + return Promise.resolve(); + } + // TODO don't make simulatneous requests for the same users (question: what + // will actually cause this situation to arise? Receiving lots of messages + // in a room from a user who is no longer a member of said room?) + return _this.instance.request({ + method: 'GET', + path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') + }).then(pipe(JSON.parse, map(parseUser), forEach(function (user) { + return _this.set(user.id, user); + }))).catch(function (err) { + _this.logger.warn('error fetching missing users:', err); + throw err; + }); + }; + + this.snapshot = function () { + return map(_this.decorate, _this.store.snapshot()); + }; + + this.getSync = function (userId) { + return _this.decorate(_this.store.getSync(userId)); + }; + + this.decorate = function (user) { + return user ? _extends({}, user, { presence: _this.presenceStore.getSync(user.id) }) : undefined; + }; + + this.instance = instance; + this.presenceStore = presenceStore; + this.logger = logger; +}; + +var Room = function () { + function Room(basicRoom, userStore) { + classCallCheck(this, Room); + + this.createdAt = basicRoom.createdAt; + this.createdByUserId = basicRoom.createdByUserId; + this.deletedAt = basicRoom.deletedAt; + this.id = basicRoom.id; + this.isPrivate = basicRoom.isPrivate; + this.name = basicRoom.name; + this.updatedAt = basicRoom.updatedAt; + this.userIds = basicRoom.userIds; + this.userStore = userStore; + } + + createClass(Room, [{ + key: 'users', + get: function get$$1() { + var _this = this; + + return filter(function (user) { + return contains$1(user.id, _this.userIds); + }, values(this.userStore.snapshot())); + } + }]); + return Room; +}(); + +var RoomStore = function RoomStore(_ref) { + var _this = this; + + var instance = _ref.instance, + userStore = _ref.userStore, + logger = _ref.logger; + classCallCheck(this, RoomStore); + this.store = new Store(); + this.initialize = this.store.initialize; + this.set = curry(function (roomId, basicRoom) { + return _this.store.set(roomId, basicRoom).then(_this.decorate).then(function (room) { + return _this.userStore.fetchMissingUsers(room.userIds).then(function () { + return room; + }); + }); + }); + + this.get = function (roomId) { + return _this.store.get(roomId).then(function (basicRoom) { + return basicRoom || _this.fetchBasicRoom(roomId).then(_this.set(roomId)); + }).then(_this.decorate); + }; + + this.pop = function (roomId) { + return _this.store.pop(roomId).then(function (basicRoom) { + return basicRoom || _this.fetchBasicRoom(roomId); + }).then(_this.decorate); + }; + + this.addUserToRoom = function (roomId, userId) { + return _this.pop(roomId).then(function (r) { + return _this.set(roomId, _extends({}, r, { userIds: uniq(append(userId, r.userIds)) })); + }); + }; + + this.removeUserFromRoom = function (roomId, userId) { + return _this.pop(roomId).then(function (r) { + return _this.set(roomId, _extends({}, r, { userIds: filter(function (id) { + return id !== userId; + }, r.userIds) })); + }); + }; + + this.update = function (roomId, updates) { + return _this.store.pop(roomId).then(function (r) { + return _this.set(roomId, mergeWith(function (x, y) { + return y || x; + }, r, updates)); + }); + }; + + this.fetchBasicRoom = function (roomId) { + return _this.instance.request({ + method: 'GET', + path: '/rooms/' + roomId + }).then(pipe(JSON.parse, parseBasicRoom)).catch(function (err) { + _this.logger.warn('error fetching details for room ' + roomId + ':', err); + }); + }; + + this.snapshot = function () { + return map(_this.decorate, _this.store.snapshot()); + }; + + this.getSync = function (roomId) { + return _this.decorate(_this.store.getSync(roomId)); + }; + + this.decorate = function (basicRoom) { + return basicRoom ? new Room(basicRoom, _this.userStore) : undefined; + }; + + this.instance = instance; + this.userStore = userStore; + this.logger = logger; +}; + +var TYPING_INDICATOR_TTL = 1500; +var TYPING_INDICATOR_LEEWAY = 500; + +var TypingIndicators = function TypingIndicators(_ref) { + var _this = this; + + var userId = _ref.userId, + instance = _ref.instance, + logger = _ref.logger; + classCallCheck(this, TypingIndicators); + + this.sendThrottledRequest = function (roomId) { + var now = Date.now(); + var sent = _this.lastSentRequests[roomId]; + if (sent && now - sent < TYPING_INDICATOR_TTL - TYPING_INDICATOR_LEEWAY) { + return Promise.resolve(); + } + _this.lastSentRequests[roomId] = now; + return _this.instance.request({ + method: 'POST', + path: '/rooms/' + roomId + '/events', + json: { + name: 'typing_start', // soon to be 'is_typing' + user_id: _this.userId + } + }).catch(function (err) { + delete _this.typingRequestSent[roomId]; + _this.logger.warn('Error sending is_typing event in room ' + roomId, err); + throw err; + }); + }; + + this.onIsTyping = function (room, user, hooks, roomHooks) { + if (!_this.timers[room.id]) { + _this.timers[room.id] = {}; + } + if (_this.timers[room.id][user.id]) { + clearTimeout(_this.timers[room.id][user.id]); + } else { + _this.onStarted(room, user, hooks, roomHooks); + } + _this.timers[room.id][user.id] = setTimeout(function () { + _this.onStopped(room, user, hooks, roomHooks); + delete _this.timers[room.id][user.id]; + }, TYPING_INDICATOR_TTL); + }; + + this.onStarted = function (room, user, hooks, roomHooks) { + if (hooks.userStartedTyping) { + hooks.userStartedTyping(room, user); + } + if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { + roomHooks[room.id].userStartedTyping(user); + } + }; + + this.onStopped = function (room, user, hooks, roomHooks) { + if (hooks.userStoppedTyping) { + hooks.userStoppedTyping(room, user); + } + if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { + roomHooks[room.id].userStoppedTyping(user); + } + }; + + this.userId = userId; + this.instance = instance; + this.logger = logger; + this.lastSentRequests = {}; + this.timers = {}; +}; + +var UserSubscription = function () { + function UserSubscription(options) { + var _this = this; + + classCallCheck(this, UserSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'initial_state': + _this.onInitialState(body.data); + break; + case 'added_to_room': + _this.onAddedToRoom(body.data); + break; + case 'removed_from_room': + _this.onRemovedFromRoom(body.data); + break; + case 'user_joined': + _this.onUserJoined(body.data); + break; + case 'user_left': + _this.onUserLeft(body.data); + break; + case 'room_updated': + _this.onRoomUpdated(body.data); + break; + case 'room_deleted': + _this.onRoomDeleted(body.data); + break; + case 'typing_start': + // soon to be 'is_typing' + _this.onIsTyping(body.data); + break; + } + }; + + this.onInitialState = function (_ref2) { + var userData = _ref2.current_user, + roomsData = _ref2.rooms; + + _this.hooks.subscriptionEstablished({ + user: parseUser(userData), + basicRooms: map(parseBasicRoom, roomsData) + }); + }; + + this.onAddedToRoom = function (_ref3) { + var roomData = _ref3.room; + + var basicRoom = parseBasicRoom(roomData); + _this.roomStore.set(basicRoom.id, basicRoom).then(function (room) { + if (_this.hooks.addedToRoom) { + _this.hooks.addedToRoom(room); + } + }); + }; + + this.onRemovedFromRoom = function (_ref4) { + var roomId = _ref4.room_id; + + _this.roomStore.pop(roomId).then(function (room) { + // room will be undefined if we left with leaveRoom + if (room && _this.hooks.removedFromRoom) { + _this.hooks.removedFromRoom(room); + } + }); + }; + + this.onUserJoined = function (_ref5) { + var roomId = _ref5.room_id, + userId = _ref5.user_id; + + _this.roomStore.addUserToRoom(roomId, userId).then(function (room) { + _this.userStore.get(userId).then(function (user) { + if (_this.hooks.userJoinedRoom) { + _this.hooks.userJoinedRoom(room, user); + } + if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userJoined) { + _this.roomSubscriptions[roomId].hooks.userJoined(user); + } + }); + }); + }; + + this.onUserLeft = function (_ref6) { + var roomId = _ref6.room_id, + userId = _ref6.user_id; + + _this.roomStore.removeUserFromRoom(roomId, userId).then(function (room) { + _this.userStore.get(userId).then(function (user) { + if (_this.hooks.userLeftRoom) { + _this.hooks.userLeftRoom(room, user); + } + if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userLeft) { + _this.roomSubscriptions[roomId].hooks.userLeft(user); + } + }); + }); + }; + + this.onRoomUpdated = function (_ref7) { + var roomData = _ref7.room; + + var updates = parseBasicRoom(roomData); + _this.roomStore.update(updates.id, updates).then(function (room) { + if (_this.hooks.roomUpdated) { + _this.hooks.roomUpdated(room); + } + }); + }; + + this.onRoomDeleted = function (_ref8) { + var roomId = _ref8.room_id; + + _this.roomStore.pop(roomId).then(function (room) { + if (room && _this.hooks.roomDeleted) { + _this.hooks.roomDeleted(room); + } + }); + }; + + this.onIsTyping = function (_ref9) { + var roomId = _ref9.room_id, + userId = _ref9.user_id; + + Promise.all([_this.roomStore.get(roomId), _this.userStore.get(userId)]).then(function (_ref10) { + var _ref11 = slicedToArray(_ref10, 2), + room = _ref11[0], + user = _ref11[1]; + + return _this.typingIndicators.onIsTyping(room, user, _this.hooks, map(prop('hooks'), _this.roomSubscriptions)); + }); + }; + + this.userId = options.userId; + this.hooks = options.hooks; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.typingIndicators = options.typingIndicators; + this.roomSubscriptions = options.roomSubscriptions; + } + + createClass(UserSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); + _this2.instance.subscribeNonResuming({ + path: '/users', + listeners: { + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return UserSubscription; +}(); + +var PresenceSubscription = function () { + function PresenceSubscription(options) { + var _this = this; + + classCallCheck(this, PresenceSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'initial_state': + _this.onInitialState(body.data); + break; + case 'presence_update': + _this.onPresenceUpdate(body.data); + break; + case 'join_room_presence_update': + _this.onJoinRoomPresenceUpdate(body.data); + break; + } + }; + + this.onInitialState = function (_ref2) { + var userStates = _ref2.user_states; + + _this.presenceStore.initialize(indexBy(prop('userId'), map(parsePresence, userStates))); + _this.hooks.subscriptionEstablished(); + }; + + this.onPresenceUpdate = function (data) { + var presence = parsePresence(data); + _this.presenceStore.set(presence.userId, presence).then(function (p) { + return _this.userStore.get(p.userId).then(function (user) { + switch (p.state) { + case 'online': + _this.onCameOnline(user); + break; + case 'offline': + _this.onWentOffline(user); + break; + } + }); + }); + }; + + this.onJoinRoomPresenceUpdate = function (_ref3) { + var userStates = _ref3.user_states; + return forEach(function (presence) { + return _this.presenceStore.set(presence.userId, presence); + }, map(parsePresence, userStates)); + }; + + this.onCameOnline = function (user) { + return _this.callRelevantHooks('userCameOnline', user); + }; + + this.onWentOffline = function (user) { + return _this.callRelevantHooks('userWentOffline', user); + }; + + this.callRelevantHooks = function (hookName, user) { + if (_this.hooks[hookName]) { + _this.hooks[hookName](user); + } + compose(forEach(function (sub) { + return _this.roomStore.get(sub.roomId).then(function (room) { + if (contains$1(user.id, room.userIds)) { + sub.hooks[hookName](user); + } + }); + }), filter(function (sub) { + return sub.hooks[hookName] !== undefined; + }), values)(_this.roomSubscriptions); + }; + + this.userId = options.userId; + this.hooks = options.hooks; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.presenceStore = options.presenceStore; + this.roomSubscriptions = options.roomSubscriptions; + } + + createClass(PresenceSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); + _this2.instance.subscribeNonResuming({ + path: '/users/' + encodeURIComponent(_this2.userId) + '/presence', + listeners: { + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return PresenceSubscription; +}(); + +var Message = function () { + function Message(basicMessage, userStore, roomStore) { + classCallCheck(this, Message); + + this.id = basicMessage.id; + this.senderId = basicMessage.senderId; + this.roomId = basicMessage.roomId; + this.text = basicMessage.text; + this.attachment = basicMessage.attachment; + this.createdAt = basicMessage.createdAt; + this.updatedAt = basicMessage.updatedAt; + this.userStore = userStore; + this.roomStore = roomStore; + } + + createClass(Message, [{ + key: "sender", + get: function get$$1() { + return this.userStore.getSync(this.senderId); + } + }, { + key: "room", + get: function get$$1() { + return this.roomStore.getSync(this.roomId); + } + }]); + return Message; +}(); + +var RoomSubscription = function () { + function RoomSubscription(options) { + var _this = this; + + classCallCheck(this, RoomSubscription); + + this.onEvent = function (_ref) { + var body = _ref.body; + + switch (body.event_name) { + case 'new_message': + _this.onNewMessage(body.data); + break; + } + }; + + this.onNewMessage = function (data) { + var pending = { + message: new Message(parseBasicMessage(data), _this.userStore, _this.roomStore), + ready: false + }; + _this.messageBuffer.push(pending); + _this.userStore.fetchMissingUsers([pending.message.senderId]).catch(function (err) { + _this.logger.error('error fetching missing user information:', err); + }).then(function () { + pending.ready = true; + _this.flushBuffer(); + }); + }; + + this.flushBuffer = function () { + while (!isEmpty(_this.messageBuffer) && head(_this.messageBuffer).ready) { + var message = _this.messageBuffer.shift().message; + if (_this.hooks.newMessage) { + _this.hooks.newMessage(message); + } + } + }; + + this.roomId = options.roomId; + this.hooks = options.hooks; + this.messageLimit = options.messageLimit; + this.userId = options.userId; + this.instance = options.instance; + this.userStore = options.userStore; + this.roomStore = options.roomStore; + this.messageBuffer = []; // { message, ready } + } + + createClass(RoomSubscription, [{ + key: 'connect', + value: function connect() { + var _this2 = this; + + return new Promise(function (resolve, reject) { + _this2.instance.subscribeNonResuming({ + path: '/rooms/' + _this2.roomId + '?' + urlEncode({ + message_limit: _this2.messageLimit + }), + listeners: { + onOpen: resolve, + onError: reject, + onEvent: _this2.onEvent + } + }); + }); + } + }]); + return RoomSubscription; +}(); + +var CurrentUser = function () { + function CurrentUser(_ref) { + var _this = this; + + var id = _ref.id, + apiInstance = _ref.apiInstance, + filesInstance = _ref.filesInstance; + classCallCheck(this, CurrentUser); + + this.isTypingIn = function (roomId) { + typeCheck('roomId', 'number', roomId); + return _this.typingIndicators.sendThrottledRequest(roomId); + }; + + this.createRoom = function () { + var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var name = _ref2.name, + addUserIds = _ref2.addUserIds, + rest = objectWithoutProperties(_ref2, ['name', 'addUserIds']); + + name && typeCheck('name', 'string', name); + addUserIds && typeCheckArr('addUserIds', 'string', addUserIds); + return _this.apiInstance.request({ + method: 'POST', + path: '/rooms', + json: { + created_by_id: _this.id, + name: name, + private: !!rest.private, // private is a reserved word in strict mode! + user_ids: addUserIds + } + }).then(function (res) { + var basicRoom = parseBasicRoom(JSON.parse(res)); + return _this.roomStore.set(basicRoom.id, basicRoom); + }).catch(function (err) { + _this.logger.warn('error creating room:', err); + throw err; + }); + }; + + this.getJoinableRooms = function () { + return _this.apiInstance.request({ + method: 'GET', + path: '/users/' + _this.encodedId + '/rooms?joinable=true' + }).then(pipe(JSON.parse, map(parseBasicRoom))).catch(function (err) { + _this.logger.warn('error getting joinable rooms:', err); + throw err; + }); + }; + + this.getAllRooms = function () { + return _this.getJoinableRooms().then(concat(_this.rooms)); + }; + + this.joinRoom = function (roomId) { + typeCheck('roomId', 'number', roomId); + if (_this.isMemberOf(roomId)) { + return _this.roomStore.get(roomId); + } + return _this.apiInstance.request({ + method: 'POST', + path: '/users/' + _this.encodedId + '/rooms/' + roomId + '/join' + }).then(function (res) { + var basicRoom = parseBasicRoom(JSON.parse(res)); + return _this.roomStore.set(basicRoom.id, basicRoom); + }).catch(function (err) { + _this.logger.warn('error joining room ' + roomId + ':', err); + throw err; + }); + }; + + this.leaveRoom = function (roomId) { + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'POST', + path: '/users/' + _this.encodedId + '/rooms/' + roomId + '/leave' + }).then(function () { + return _this.roomStore.pop(roomId); + }).catch(function (err) { + _this.logger.warn('error leaving room ' + roomId + ':', err); + throw err; + }); + }; + + this.addUser = function (userId, roomId) { + typeCheck('userId', 'string', userId); + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'PUT', + path: '/rooms/' + roomId + '/users/add', + json: { + user_ids: [userId] + } + }).then(function () { + return _this.roomStore.addUserToRoom(roomId, userId); + }).catch(function (err) { + _this.logger.warn('error adding user ' + userId + ' to room ' + roomId + ':', err); + throw err; + }); + }; + + this.removeUser = function (userId, roomId) { + typeCheck('userId', 'string', userId); + typeCheck('roomId', 'number', roomId); + return _this.apiInstance.request({ + method: 'PUT', + path: '/rooms/' + roomId + '/users/remove', + json: { + user_ids: [userId] + } + }).then(function () { + return _this.roomStore.removeUserFromRoom(roomId, userId); + }).catch(function (err) { + _this.logger.warn('error removing user ' + userId + ' from room ' + roomId + ':', err); + throw err; + }); + }; + + this.sendMessage = function (_ref3) { + var text = _ref3.text, + roomId = _ref3.roomId, + attachment = _ref3.attachment; + + typeCheck('text', 'string', text); + typeCheck('roomId', 'number', roomId); + return new Promise(function (resolve, reject) { + if (attachment !== undefined && isDataAttachment(attachment)) { + resolve(_this.uploadDataAttachment(roomId, attachment)); + } else if (attachment !== undefined && isLinkAttachment(attachment)) { + resolve({ resource_link: attachment.link, type: attachment.type }); + } else if (attachment !== undefined) { + reject(new TypeError('attachment was malformed')); + } else { + resolve(); + } + }).then(function (attachment) { + return _this.apiInstance.request({ + method: 'POST', + path: '/rooms/' + roomId + '/messages', + json: { text: text, attachment: attachment } + }); + }).then(pipe(JSON.parse, prop('message_id'))).catch(function (err) { + _this.logger.warn('error sending message to room ' + roomId + ':', err); + throw err; + }); + }; + + this.fetchMessages = function (roomId) { + var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + initialId = _ref4.initialId, + limit = _ref4.limit, + direction = _ref4.direction; + + typeCheck('roomId', 'number', roomId); + initialId && typeCheck('initialId', 'number', initialId); + limit && typeCheck('limit', 'number', limit); + direction && checkOneOf('direction', ['older', 'newer'], direction); + return _this.apiInstance.request({ + method: 'GET', + path: '/rooms/' + roomId + '/messages?' + urlEncode({ + initial_id: initialId, + limit: limit, + direction: direction + }) + }).then(function (res) { + var messages = map(compose(_this.decorateMessage, parseBasicMessage), JSON.parse(res)); + return _this.userStore.fetchMissingUsers(uniq(map(prop('senderId'), messages))).then(function () { + return sort(function (x, y) { + return x.id - y.id; + }, messages); + }); + }).catch(function (err) { + _this.logger.warn('error fetching messages from room ' + roomId + ':', err); + throw err; + }); + }; + + this.subscribeToRoom = function (roomId) { + var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var messageLimit = arguments[2]; + + typeCheck('roomId', 'number', roomId); + typeCheckObj('hooks', 'function', hooks); + messageLimit && typeCheck('messageLimit', 'number', messageLimit); + // TODO what is the desired behaviour if there is already a subscription to + // this room? Close the old one? Throw an error? Merge the hooks? + _this.roomSubscriptions[roomId] = new RoomSubscription({ + roomId: roomId, + hooks: hooks, + messageLimit: messageLimit, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + logger: _this.logger + }); + return _this.joinRoom(roomId).then(function (room) { + return _this.roomSubscriptions[roomId].connect().then(function () { + return room; + }); + }).catch(function (err) { + return _this.logger.error('error subscribing to room ' + roomId, err); + }); + }; + + this.uploadDataAttachment = function (roomId, _ref5) { + var file = _ref5.file, + name = _ref5.name; + + // TODO some validation on allowed file names? + // TODO polyfill FormData? + var body = new FormData(); // eslint-disable-line no-undef + body.append('file', file, name); + return _this.filesInstance.request({ + method: 'POST', + path: '/rooms/' + roomId + '/files/' + name, + body: body + }).then(JSON.parse); + }; + + this.isMemberOf = function (roomId) { + return contains$1(roomId, map(prop('id'), _this.rooms)); + }; + + this.decorateMessage = function (basicMessage) { + return new Message(basicMessage, _this.userStore, _this.roomStore); + }; + + this.establishUserSubscription = function (hooks) { + _this.userSubscription = new UserSubscription({ + hooks: hooks, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + typingIndicators: _this.typingIndicators, + roomSubscriptions: _this.roomSubscriptions + }); + return _this.userSubscription.connect().then(function (_ref6) { + var user = _ref6.user, + basicRooms = _ref6.basicRooms; + + _this.avatarURL = user.avatarURL; + _this.createdAt = user.createdAt; + _this.customData = user.customData; + _this.name = user.name; + _this.updatedAt = user.updatedAt; + _this.roomStore.initialize(indexBy(prop('id'), basicRooms)); + }).then(_this.initializeUserStore); + }; + + this.establishPresenceSubscription = function (hooks) { + _this.presenceSubscription = new PresenceSubscription({ + hooks: hooks, + userId: _this.id, + instance: _this.apiInstance, + userStore: _this.userStore, + roomStore: _this.roomStore, + presenceStore: _this.presenceStore, + roomSubscriptions: _this.roomSubscriptions + }); + return _this.presenceSubscription.connect(); + }; + + this.initializeUserStore = function () { + return _this.userStore.fetchMissingUsers(uniq(chain(prop('userIds'), _this.rooms))).catch(function (err) { + _this.logger.warn('error fetching initial user information:', err); + }).then(function () { + _this.userStore.initialize({}); + }); + }; + + this.id = id; + this.encodedId = encodeURIComponent(this.id); + this.apiInstance = apiInstance; + this.filesInstance = filesInstance; + this.logger = apiInstance.logger; + this.presenceStore = new Store(); + this.userStore = new UserStore({ + instance: this.apiInstance, + presenceStore: this.presenceStore, + logger: this.logger + }); + this.roomStore = new RoomStore({ + instance: this.apiInstance, + userStore: this.userStore, + logger: this.logger + }); + this.typingIndicators = new TypingIndicators({ + userId: this.id, + instance: this.apiInstance, + logger: this.logger + }); + this.roomSubscriptions = {}; + } + + /* public */ + + createClass(CurrentUser, [{ + key: 'rooms', + get: function get$$1() { + return values(this.roomStore.snapshot()); + } + }, { + key: 'users', + get: function get$$1() { + return values(this.userStore.snapshot()); + } + + /* internal */ + + }]); + return CurrentUser; +}(); + +var isDataAttachment = function isDataAttachment(_ref7) { + var file = _ref7.file, + name = _ref7.name; + + if (file === undefined || name === undefined) { + return false; + } + typeCheck('attachment.file', 'object', file); + typeCheck('attachment.name', 'string', name); + return true; +}; + +var isLinkAttachment = function isLinkAttachment(_ref8) { + var link = _ref8.link, + type = _ref8.type; + + if (link === undefined || type === undefined) { + return false; + } + typeCheck('attachment.link', 'string', link); + typeCheck('attachment.type', 'string', type); + return true; +}; + +var ChatManager = function ChatManager() { + var _this = this; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var instanceLocator = _ref.instanceLocator, + tokenProvider = _ref.tokenProvider, + userId = _ref.userId, + options = objectWithoutProperties(_ref, ['instanceLocator', 'tokenProvider', 'userId']); + classCallCheck(this, ChatManager); + + this.connect = function () { + var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + typeCheckObj('hooks', 'function', hooks); + var currentUser = new CurrentUser({ + id: _this.userId, + apiInstance: _this.apiInstance, + filesInstance: _this.filesInstance + }); + return Promise.all([currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) + // currentUser.initializeCursorStore() + ]).then(function () { + return currentUser; + }); + }; + + typeCheck('instanceLocator', 'string', instanceLocator); + typeCheck('tokenProvider', 'object', tokenProvider); + typeCheck('tokenProvider.fetchToken', 'function', tokenProvider.fetchToken); + typeCheck('userId', 'string', userId); + var cluster = split(':', instanceLocator)[1]; + if (cluster === undefined) { + throw new TypeError('expected instanceLocator to be of the format x:y:z, but was ' + instanceLocator); + } + var baseClient = options.baseClient || new pusherPlatform_1({ + host: cluster + '.' + pusherPlatform_2, + logger: options.logger + }); + if (typeof tokenProvider.setUserId === 'function') { + tokenProvider.setUserId(userId); + } + var instanceOptions = { + client: baseClient, + locator: instanceLocator, + logger: options.logger, + tokenProvider: tokenProvider + }; + this.apiInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit', + serviceVersion: 'v1' + }, instanceOptions)); + this.filesInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit_files', + serviceVersion: 'v1' + }, instanceOptions)); + this.cursorsInstance = new pusherPlatform_3(_extends({ + serviceName: 'chatkit_cursors', + serviceVersion: 'v1' + }, instanceOptions)); + this.userId = userId; +}; + +var main = { TokenProvider: TokenProvider, ChatManager: ChatManager }; + +return main; + +}))); From 77417245ca7d07bc76143dc2313eed81a32d5b49 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 20 Feb 2018 17:03:41 +0000 Subject: [PATCH 59/99] fetchAttachment --- dist/web/chatkit.js | 132 ++++++++++++++++++++++++++------------------ src/current-user.js | 29 ++++++++-- src/parsers.js | 14 ++++- 3 files changed, 115 insertions(+), 60 deletions(-) diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js index 8bf5868..b6cd7c0 100644 --- a/dist/web/chatkit.js +++ b/dist/web/chatkit.js @@ -5684,6 +5684,70 @@ function TokenProvider() { this.url = url; }; +var parseBasicRoom = function parseBasicRoom(data) { + return { + createdAt: data.created_at, + createdByUserId: data.created_by_id, + deletedAt: data.deletedAt, + id: data.id, + isPrivate: data.private, + name: data.name, + updatedAt: data.updated_at, + userIds: data.member_user_ids + }; +}; + +var parseUser = function parseUser(data) { + return { + avatarURL: data.avatar_url, + createdAt: data.created_at, + customData: data.custom_data, + id: data.id, + name: data.name, + updatedAt: data.updated_at + }; +}; + +var parsePresence = function parsePresence(data) { + return { + lastSeenAt: data.last_seen_at, + state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', + userId: data.user_id + }; +}; + +var parseBasicMessage = function parseBasicMessage(data) { + return { + id: data.id, + senderId: data.user_id, + roomId: data.room_id, + text: data.text, + createdAt: data.created_at, + updatedAt: data.updated_at, + attachment: data.attachment && parseMessageAttachment(data.attachment) + }; +}; + +var parseFetchedAttachment = function parseFetchedAttachment(data) { + return { + file: { + name: data.file.name, + bytes: data.file.bytes, + lastModified: data.file.last_modified + }, + link: data.resource_link, + ttl: data.ttl + }; +}; + +var parseMessageAttachment = function parseMessageAttachment(data) { + return { + link: data.resource_link, + type: data.type, + fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' + }; +}; + var Store = function Store() { var _this = this; @@ -5744,58 +5808,6 @@ var Store = function Store() { }; }; -var parseBasicRoom = function parseBasicRoom(data) { - return { - createdAt: data.created_at, - createdByUserId: data.created_by_id, - deletedAt: data.deletedAt, - id: data.id, - isPrivate: data.private, - name: data.name, - updatedAt: data.updated_at, - userIds: data.member_user_ids - }; -}; - -var parseUser = function parseUser(data) { - return { - avatarURL: data.avatar_url, - createdAt: data.created_at, - customData: data.custom_data, - id: data.id, - name: data.name, - updatedAt: data.updated_at - }; -}; - -var parsePresence = function parsePresence(data) { - return { - lastSeenAt: data.last_seen_at, - state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', - userId: data.user_id - }; -}; - -var parseBasicMessage = function parseBasicMessage(data) { - return { - id: data.id, - senderId: data.user_id, - roomId: data.room_id, - text: data.text, - createdAt: data.created_at, - updatedAt: data.updated_at, - attachment: data.attachment && parseAttachment(data.attachment) - }; -}; - -var parseAttachment = function parseAttachment(data) { - return { - link: data.resource_link, - type: data.type, - fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' - }; -}; - var UserStore = function UserStore(_ref) { var _this = this; @@ -6617,7 +6629,21 @@ var CurrentUser = function () { return room; }); }).catch(function (err) { - return _this.logger.error('error subscribing to room ' + roomId, err); + _this.logger.warn('error subscribing to room ' + roomId + ':', err); + throw err; + }); + }; + + this.fetchAttachment = function (url) { + return _this.filesInstance.tokenProvider.fetchToken().then(function (token) { + return pusherPlatform_4({ + method: 'GET', + headers: { Authorization: 'Bearer ' + token }, + url: url + }); + }).then(pipe(JSON.parse, parseFetchedAttachment)).catch(function (err) { + _this.logger.warn('error fetching attachment:', err); + throw err; }); }; diff --git a/src/current-user.js b/src/current-user.js index e7a21bb..9379db6 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -1,3 +1,4 @@ +import { sendRawRequest } from 'pusher-platform' import { chain, compose, @@ -19,10 +20,14 @@ import { typeCheckObj, urlEncode } from './utils' +import { + parseBasicMessage, + parseBasicRoom, + parseFetchedAttachment +} from './parsers' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' -import { parseBasicRoom, parseBasicMessage } from './parsers' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' @@ -256,10 +261,24 @@ export class CurrentUser { }) return this.joinRoom(roomId) .then(room => this.roomSubscriptions[roomId].connect().then(() => room)) - .catch(err => this.logger.error( - `error subscribing to room ${roomId}`, - err - )) + .catch(err => { + this.logger.warn(`error subscribing to room ${roomId}:`, err) + throw err + }) + } + + fetchAttachment = url => { + return this.filesInstance.tokenProvider.fetchToken() + .then(token => sendRawRequest({ + method: 'GET', + headers: { Authorization: `Bearer ${token}` }, + url + })) + .then(pipe(JSON.parse, parseFetchedAttachment)) + .catch(err => { + this.logger.warn(`error fetching attachment:`, err) + throw err + }) } /* internal */ diff --git a/src/parsers.js b/src/parsers.js index d478acd..026e043 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -35,10 +35,20 @@ export const parseBasicMessage = data => ({ text: data.text, createdAt: data.created_at, updatedAt: data.updated_at, - attachment: data.attachment && parseAttachment(data.attachment) + attachment: data.attachment && parseMessageAttachment(data.attachment) }) -const parseAttachment = data => ({ +export const parseFetchedAttachment = data => ({ + file: { + name: data.file.name, + bytes: data.file.bytes, + lastModified: data.file.last_modified + }, + link: data.resource_link, + ttl: data.ttl +}) + +const parseMessageAttachment = data => ({ link: data.resource_link, type: data.type, fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' From f0b7b1323d1904859e15d4e883c1aabc8745e741 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 21 Feb 2018 16:04:42 +0000 Subject: [PATCH 60/99] publish prerelease to npm (so can remove dist) --- dist/web/chatkit.js | 6851 ------------------------------------------- package.json | 2 +- 2 files changed, 1 insertion(+), 6852 deletions(-) delete mode 100644 dist/web/chatkit.js diff --git a/dist/web/chatkit.js b/dist/web/chatkit.js deleted file mode 100644 index b6cd7c0..0000000 --- a/dist/web/chatkit.js +++ /dev/null @@ -1,6851 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Chatkit = factory()); -}(this, (function () { 'use strict'; - -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - - -function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -var pusherPlatform = createCommonjsModule(function (module, exports) { -(function webpackUniversalModuleDefinition(root, factory) { - module.exports = factory(); -})(commonjsGlobal, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -function responseToHeadersObject(headerStr) { - var headers = {}; - if (!headerStr) { - return headers; - } - var headerPairs = headerStr.split('\u000d\u000a'); - for (var _i = 0, headerPairs_1 = headerPairs; _i < headerPairs_1.length; _i++) { - var headerPair = headerPairs_1[_i]; - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - return headers; -} -exports.responseToHeadersObject = responseToHeadersObject; -var ErrorResponse = (function () { - function ErrorResponse(statusCode, headers, info) { - this.statusCode = statusCode; - this.headers = headers; - this.info = info; - } - ErrorResponse.fromXHR = function (xhr) { - var errorInfo = xhr.responseText; - try { - errorInfo = JSON.parse(xhr.responseText); - } - catch (e) { - } - return new ErrorResponse(xhr.status, responseToHeadersObject(xhr.getAllResponseHeaders()), errorInfo); - }; - return ErrorResponse; -}()); -exports.ErrorResponse = ErrorResponse; -var NetworkError = (function () { - function NetworkError(error) { - this.error = error; - } - return NetworkError; -}()); -exports.NetworkError = NetworkError; -var XhrReadyState; -(function (XhrReadyState) { - XhrReadyState[XhrReadyState["UNSENT"] = 0] = "UNSENT"; - XhrReadyState[XhrReadyState["OPENED"] = 1] = "OPENED"; - XhrReadyState[XhrReadyState["HEADERS_RECEIVED"] = 2] = "HEADERS_RECEIVED"; - XhrReadyState[XhrReadyState["LOADING"] = 3] = "LOADING"; - XhrReadyState[XhrReadyState["DONE"] = 4] = "DONE"; -})(XhrReadyState = exports.XhrReadyState || (exports.XhrReadyState = {})); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var LogLevel; -(function (LogLevel) { - LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; - LogLevel[LogLevel["DEBUG"] = 2] = "DEBUG"; - LogLevel[LogLevel["INFO"] = 3] = "INFO"; - LogLevel[LogLevel["WARNING"] = 4] = "WARNING"; - LogLevel[LogLevel["ERROR"] = 5] = "ERROR"; -})(LogLevel = exports.LogLevel || (exports.LogLevel = {})); -var ConsoleLogger = (function () { - function ConsoleLogger(threshold) { - if (threshold === void 0) { threshold = 2; } - this.threshold = threshold; - var groups = Array(); - var hr = '--------------------------------------------------------------------------------'; - if (!window.console.group) { - window.console.group = function (label) { - groups.push(label); - window.console.log('%c \nBEGIN GROUP: %c', hr, label); - }; - } - if (!window.console.groupEnd) { - window.console.groupEnd = function () { - window.console.log('END GROUP: %c\n%c', groups.pop(), hr); - }; - } - } - ConsoleLogger.prototype.verbose = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.log, LogLevel.VERBOSE, items); - }; - ConsoleLogger.prototype.debug = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.log, LogLevel.DEBUG, items); - }; - ConsoleLogger.prototype.info = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.info, LogLevel.INFO, items); - }; - ConsoleLogger.prototype.warn = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.warn, LogLevel.WARNING, items); - }; - ConsoleLogger.prototype.error = function () { - var items = []; - for (var _i = 0; _i < arguments.length; _i++) { - items[_i] = arguments[_i]; - } - this.log(window.console.error, LogLevel.ERROR, items); - }; - ConsoleLogger.prototype.log = function (logFunction, level, items) { - var _this = this; - if (level >= this.threshold) { - var loggerSignature_1 = "Logger." + LogLevel[level]; - if (items.length > 1) { - window.console.group(); - items.forEach(function (item) { - _this.errorAwareLog(logFunction, item, loggerSignature_1); - }); - window.console.groupEnd(); - } - else { - this.errorAwareLog(logFunction, items[0], loggerSignature_1); - } - } - }; - ConsoleLogger.prototype.errorAwareLog = function (logFunction, item, loggerSignature) { - if (item.info && item.info.error_uri) { - var errorDesc = item.info.error_description; - var errorIntro = errorDesc ? errorDesc : 'An error has occurred'; - logFunction(errorIntro + ". More information can be found at " + item.info.error_uri + ". Error object: ", item); - } - else { - logFunction(loggerSignature + ": ", item); - } - }; - return ConsoleLogger; -}()); -exports.ConsoleLogger = ConsoleLogger; -var EmptyLogger = (function () { - function EmptyLogger() { - } - EmptyLogger.prototype.verbose = function (message, error) { }; - EmptyLogger.prototype.debug = function (message, error) { }; - EmptyLogger.prototype.info = function (message, error) { }; - EmptyLogger.prototype.warn = function (message, error) { }; - EmptyLogger.prototype.error = function (message, error) { }; - return EmptyLogger; -}()); -exports.EmptyLogger = EmptyLogger; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createRetryStrategyOptionsOrDefault = function (options) { - var initialTimeoutMillis = options.initialTimeoutMillis || 1000; - var maxTimeoutMillis = options.maxTimeoutMillis || 5000; - var limit = -1; - if (options.limit !== undefined && options.limit != null) { - limit = options.limit; - } - var increaseTimeout; - if (options.increaseTimeout !== undefined) { - increaseTimeout = options.increaseTimeout; - } - else { - increaseTimeout = function (currentTimeout) { - if (currentTimeout * 2 > maxTimeoutMillis) { - return maxTimeoutMillis; - } - else { - return currentTimeout * 2; - } - }; - } - return { - increaseTimeout: increaseTimeout, - initialTimeoutMillis: initialTimeoutMillis, - limit: limit, - maxTimeoutMillis: maxTimeoutMillis, - }; -}; -var Retry = (function () { - function Retry(waitTimeMillis) { - this.waitTimeMillis = waitTimeMillis; - } - return Retry; -}()); -exports.Retry = Retry; -var DoNotRetry = (function () { - function DoNotRetry(error) { - this.error = error; - } - return DoNotRetry; -}()); -exports.DoNotRetry = DoNotRetry; -var requestMethodIsSafe = function (method) { - method = method.toUpperCase(); - return (method === 'GET' || - method === 'HEAD' || - method === 'OPTIONS' || - method === 'SUBSCRIBE'); -}; -var RetryResolution = (function () { - function RetryResolution(options, logger, retryUnsafeRequests) { - this.options = options; - this.logger = logger; - this.retryUnsafeRequests = retryUnsafeRequests; - this.currentRetryCount = 0; - this.initialTimeoutMillis = options.initialTimeoutMillis; - this.maxTimeoutMillis = options.maxTimeoutMillis; - this.limit = options.limit; - this.increaseTimeoutFunction = options.increaseTimeout; - this.currentBackoffMillis = this.initialTimeoutMillis; - } - RetryResolution.prototype.attemptRetry = function (error) { - this.logger.verbose(this.constructor.name + ": Error received", error); - if (this.currentRetryCount >= this.limit && this.limit >= 0) { - this.logger.verbose(this.constructor.name + ": Retry count is over the maximum limit: " + this.limit); - return new DoNotRetry(error); - } - if (error instanceof network_1.ErrorResponse && error.headers['Retry-After']) { - this.logger.verbose(this.constructor.name + ": Retry-After header is present, retrying in " + error.headers['Retry-After']); - return new Retry(parseInt(error.headers['Retry-After'], 10) * 1000); - } - if (error instanceof network_1.NetworkError || - (error instanceof network_1.ErrorResponse && - requestMethodIsSafe(error.headers['Request-Method'])) || - this.retryUnsafeRequests) { - return this.shouldSafeRetry(error); - } - if (error instanceof network_1.NetworkError) { - return this.shouldSafeRetry(error); - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.shouldSafeRetry = function (error) { - if (error instanceof network_1.NetworkError) { - this.logger.verbose(this.constructor.name + ": It's a Network Error, will retry", error); - return new Retry(this.calulateMillisToRetry()); - } - else if (error instanceof network_1.ErrorResponse) { - if (error.statusCode >= 500 && error.statusCode < 600) { - this.logger.verbose(this.constructor.name + ": Error 5xx, will retry"); - return new Retry(this.calulateMillisToRetry()); - } - } - this.logger.verbose(this.constructor.name + ": Error is not retryable", error); - return new DoNotRetry(error); - }; - RetryResolution.prototype.calulateMillisToRetry = function () { - this.currentBackoffMillis = this.increaseTimeoutFunction(this.currentBackoffMillis); - this.logger.verbose(this.constructor.name + ": Retrying in " + this.currentBackoffMillis + "ms"); - return this.currentBackoffMillis; - }; - return RetryResolution; -}()); -exports.RetryResolution = RetryResolution; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var logger_1 = __webpack_require__(1); -var request_1 = __webpack_require__(4); -var resuming_subscription_1 = __webpack_require__(5); -var retrying_subscription_1 = __webpack_require__(6); -var subscribe_strategy_1 = __webpack_require__(11); -var subscription_1 = __webpack_require__(12); -var token_providing_subscription_1 = __webpack_require__(7); -var http_1 = __webpack_require__(13); -var websocket_1 = __webpack_require__(14); -var transports_1 = __webpack_require__(8); -var BaseClient = (function () { - function BaseClient(options) { - this.options = options; - this.host = options.host.replace(/(\/)+$/, ''); - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.websocketTransport = new websocket_1.default(this.host); - this.httpTransport = new http_1.default(this.host, options.encrypted); - } - BaseClient.prototype.request = function (options, tokenParams) { - var _this = this; - if (options.tokenProvider) { - return options.tokenProvider - .fetchToken(tokenParams) - .then(function (token) { - if (options.headers !== undefined) { - options.headers['Authorization'] = "Bearer " + token; - } - else { - options.headers = (_a = {}, _a['Authorization'] = "Bearer " + token, _a); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - var _a; - }) - .catch(function (error) { - _this.logger.error(error); - }); - } - return request_1.executeNetworkRequest(function () { return _this.httpTransport.request(options); }, options); - }; - BaseClient.prototype.subscribeResuming = function (path, headers, listeners, retryStrategyOptions, initialEventId, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = resuming_subscription_1.createResumingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger, initialEventId); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - BaseClient.prototype.subscribeNonResuming = function (path, headers, listeners, retryStrategyOptions, tokenProvider) { - var completeListeners = subscription_1.replaceMissingListenersWithNoOps(listeners); - var subscribeStrategyListeners = subscribe_strategy_1.subscribeStrategyListenersFromSubscriptionListeners(completeListeners); - var subscriptionStrategy = retrying_subscription_1.createRetryingStrategy(retryStrategyOptions, token_providing_subscription_1.createTokenProvidingStrategy(transports_1.createTransportStrategy(path, this.websocketTransport, this.logger), this.logger, tokenProvider), this.logger); - var opened = false; - return subscriptionStrategy({ - onEnd: subscribeStrategyListeners.onEnd, - onError: subscribeStrategyListeners.onError, - onEvent: subscribeStrategyListeners.onEvent, - onOpen: function (headers) { - if (!opened) { - opened = true; - subscribeStrategyListeners.onOpen(headers); - } - completeListeners.onSubscribe(); - }, - onRetrying: subscribeStrategyListeners.onRetrying, - }, headers); - }; - return BaseClient; -}()); -exports.BaseClient = BaseClient; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -function executeNetworkRequest(createXhr, options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(createXhr(), resolve, reject); - sendBody(xhr, options); - }); -} -exports.executeNetworkRequest = executeNetworkRequest; -function sendBody(xhr, options) { - if (options.json) { - xhr.send(JSON.stringify(options.json)); - } - else { - xhr.send(options.body); - } -} -function sendRawRequest(options) { - return new Promise(function (resolve, reject) { - var xhr = attachOnReadyStateChangeHandler(new window.XMLHttpRequest(), resolve, reject); - xhr.open(options.method.toUpperCase(), options.url, true); - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - xhr.send(options.body); - }); -} -exports.sendRawRequest = sendRawRequest; -function attachOnReadyStateChangeHandler(xhr, resolve, reject) { - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status >= 200 && xhr.status < 300) { - resolve(xhr.response); - } - else if (xhr.status !== 0) { - reject(network_1.ErrorResponse.fromXHR(xhr)); - } - else { - reject(new network_1.NetworkError('No Connection')); - } - } - }; - return xhr; -} - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createResumingStrategy = function (retryOptions, nextSubscribeStrategy, logger, initialEventId) { - var completeRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(completeRetryOptions, logger); - var ResumingSubscription = (function () { - function ResumingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - this.onTransition = onTransition; - var lastEventId = initialEventId; - logger.verbose("ResumingSubscription: transitioning to OpeningSubscriptionState"); - if (lastEventId) { - headers['Last-Event-Id'] = lastEventId; - logger.verbose("ResumingSubscription: initialEventId is " + lastEventId); - } - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - onTransition(new ResumingSubscriptionState(error, onTransition, lastEventId)); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpeningSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - this.underlyingSubscription.unsubscribe(); - }; - return OpenSubscriptionState; - }()); - var ResumingSubscriptionState = (function () { - function ResumingSubscriptionState(error, onTransition, lastEventId) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("ResumingSubscription: transitioning to ResumingSubscriptionState"); - var executeSubscriptionOnce = function (error, lastEventId) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = window.setTimeout(function () { - executeNextSubscribeStrategy(lastEventId); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function (lastEventId) { - logger.verbose("ResumingSubscription: trying to re-establish the subscription"); - if (lastEventId) { - logger.verbose("ResumingSubscription: lastEventId: " + lastEventId); - headers['Last-Event-Id'] = lastEventId; - } - _this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { - onTransition(new EndedSubscriptionState(error)); - }, - onError: function (error) { - executeSubscriptionOnce(error, lastEventId); - }, - onEvent: function (event) { - lastEventId = event.eventId; - listeners.onEvent(event); - }, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error, lastEventId); - } - ResumingSubscriptionState.prototype.unsubscribe = function () { - this.onTransition(new EndingSubscriptionState()); - window.clearTimeout(this.timeout); - this.underlyingSubscription.unsubscribe(); - }; - return ResumingSubscriptionState; - }()); - var EndingSubscriptionState = (function () { - function EndingSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndingSubscriptionState"); - } - EndingSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription is already ending'); - }; - return EndingSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("ResumingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return ResumingSubscription; - }()); - return function (listeners, headers) { return new ResumingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryingStrategy = function (retryOptions, nextSubscribeStrategy, logger) { - var enrichedRetryOptions = retry_strategy_1.createRetryStrategyOptionsOrDefault(retryOptions); - var retryResolution = new retry_strategy_1.RetryResolution(enrichedRetryOptions, logger); - var RetryingSubscription = (function () { - function RetryingSubscription(listeners, headers) { - var _this = this; - this.unsubscribe = function () { - _this.state.unsubscribe(); - }; - this.onTransition = function (newState) { - _this.state = newState; - }; - var OpeningSubscriptionState = (function () { - function OpeningSubscriptionState(onTransition) { - var _this = this; - logger.verbose("RetryingSubscription: transitioning to OpeningSubscriptionState"); - this.underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { - return onTransition(new RetryingSubscriptionState(error, onTransition)); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - return onTransition(new OpenSubscriptionState(headers, _this.underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - } - OpeningSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - throw new Error('Method not implemented.'); - }; - return OpeningSubscriptionState; - }()); - var RetryingSubscriptionState = (function () { - function RetryingSubscriptionState(error, onTransition) { - var _this = this; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to RetryingSubscriptionState"); - var executeSubscriptionOnce = function (error) { - listeners.onRetrying(); - var resolveError = function (error) { - if (error instanceof network_1.ErrorResponse) { - error.headers['Request-Method'] = 'SUBSCRIBE'; - } - return retryResolution.attemptRetry(error); - }; - var errorResolution = resolveError(error); - if (errorResolution instanceof retry_strategy_1.Retry) { - _this.timeout = window.setTimeout(function () { - executeNextSubscribeStrategy(); - }, errorResolution.waitTimeMillis); - } - else { - onTransition(new FailedSubscriptionState(error)); - } - }; - var executeNextSubscribeStrategy = function () { - logger.verbose("RetryingSubscription: trying to re-establish the subscription"); - var underlyingSubscription = nextSubscribeStrategy({ - onEnd: function (error) { return onTransition(new EndedSubscriptionState(error)); }, - onError: function (error) { return executeSubscriptionOnce(error); }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - onTransition(new OpenSubscriptionState(headers, underlyingSubscription, onTransition)); - }, - onRetrying: listeners.onRetrying, - }, headers); - }; - executeSubscriptionOnce(error); - } - RetryingSubscriptionState.prototype.unsubscribe = function () { - window.clearTimeout(this.timeout); - this.onTransition(new EndedSubscriptionState()); - }; - return RetryingSubscriptionState; - }()); - var OpenSubscriptionState = (function () { - function OpenSubscriptionState(headers, underlyingSubscription, onTransition) { - this.underlyingSubscription = underlyingSubscription; - this.onTransition = onTransition; - logger.verbose("RetryingSubscription: transitioning to OpenSubscriptionState"); - listeners.onOpen(headers); - } - OpenSubscriptionState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - this.onTransition(new EndedSubscriptionState()); - }; - return OpenSubscriptionState; - }()); - var EndedSubscriptionState = (function () { - function EndedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to EndedSubscriptionState"); - listeners.onEnd(error); - } - EndedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return EndedSubscriptionState; - }()); - var FailedSubscriptionState = (function () { - function FailedSubscriptionState(error) { - logger.verbose("RetryingSubscription: transitioning to FailedSubscriptionState", error); - listeners.onError(error); - } - FailedSubscriptionState.prototype.unsubscribe = function () { - throw new Error('Subscription has already ended'); - }; - return FailedSubscriptionState; - }()); - this.state = new OpeningSubscriptionState(this.onTransition); - } - return RetryingSubscription; - }()); - return function (listeners, headers) { return new RetryingSubscription(listeners, headers); }; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -exports.createTokenProvidingStrategy = function (nextSubscribeStrategy, logger, tokenProvider) { - if (tokenProvider) { - return function (listeners, headers) { - return new TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy); - }; - } - return nextSubscribeStrategy; -}; -var TokenProvidingSubscription = (function () { - function TokenProvidingSubscription(logger, listeners, headers, tokenProvider, nextSubscribeStrategy) { - var _this = this; - this.logger = logger; - this.listeners = listeners; - this.headers = headers; - this.tokenProvider = tokenProvider; - this.nextSubscribeStrategy = nextSubscribeStrategy; - this.unsubscribe = function () { - _this.state.unsubscribe(); - _this.state = new InactiveState(_this.logger); - }; - this.state = new ActiveState(logger, headers, nextSubscribeStrategy); - this.subscribe(); - } - TokenProvidingSubscription.prototype.subscribe = function () { - var _this = this; - this.tokenProvider - .fetchToken() - .then(function (token) { - var existingListeners = Object.assign({}, _this.listeners); - _this.state.subscribe(token, { - onEnd: function (error) { - _this.state = new InactiveState(_this.logger); - existingListeners.onEnd(error); - }, - onError: function (error) { - if (_this.isTokenExpiredError(error)) { - _this.tokenProvider.clearToken(token); - _this.subscribe(); - } - else { - _this.state = new InactiveState(_this.logger); - existingListeners.onError(error); - } - }, - onEvent: _this.listeners.onEvent, - onOpen: _this.listeners.onOpen, - }); - }) - .catch(function (error) { - _this.logger.debug('TokenProvidingSubscription: error when fetching token:', error); - _this.state = new InactiveState(_this.logger); - _this.listeners.onError(error); - }); - }; - TokenProvidingSubscription.prototype.isTokenExpiredError = function (error) { - return (error instanceof network_1.ErrorResponse && - error.statusCode === 401 && - error.info === 'authentication/expired'); - }; - return TokenProvidingSubscription; -}()); -var ActiveState = (function () { - function ActiveState(logger, headers, nextSubscribeStrategy) { - this.logger = logger; - this.headers = headers; - this.nextSubscribeStrategy = nextSubscribeStrategy; - logger.verbose("TokenProvidingSubscription: transitioning to TokenProvidingState"); - } - ActiveState.prototype.subscribe = function (token, listeners) { - var _this = this; - this.putTokenIntoHeader(token); - this.underlyingSubscription = this.nextSubscribeStrategy({ - onEnd: function (error) { - _this.logger.verbose("TokenProvidingSubscription: subscription ended"); - listeners.onEnd(error); - }, - onError: function (error) { - _this.logger.verbose('TokenProvidingSubscription: subscription errored:', error); - listeners.onError(error); - }, - onEvent: listeners.onEvent, - onOpen: function (headers) { - _this.logger.verbose("TokenProvidingSubscription: subscription opened"); - listeners.onOpen(headers); - }, - onRetrying: listeners.onRetrying, - }, this.headers); - }; - ActiveState.prototype.unsubscribe = function () { - this.underlyingSubscription.unsubscribe(); - }; - ActiveState.prototype.putTokenIntoHeader = function (token) { - this.headers['Authorization'] = "Bearer " + token; - this.logger.verbose("TokenProvidingSubscription: token fetched: " + token); - }; - return ActiveState; -}()); -var InactiveState = (function () { - function InactiveState(logger) { - this.logger = logger; - logger.verbose("TokenProvidingSubscription: transitioning to OpenTokenProvidingSubscriptionState"); - } - InactiveState.prototype.subscribe = function (token, listeners) { - this.logger.verbose('TokenProvidingSubscription: subscribe called in Inactive state; doing nothing'); - }; - InactiveState.prototype.unsubscribe = function () { - this.logger.verbose('TokenProvidingSubscription: unsubscribe called in Inactive state; doing nothing'); - }; - return InactiveState; -}()); - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createTransportStrategy = function (path, transport, logger) { - return function (listeners, headers) { return transport.subscribe(path, listeners, headers); }; -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HOST_BASE = 'pusherplatform.io'; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -exports.BaseClient = base_client_1.BaseClient; -var host_base_1 = __webpack_require__(9); -exports.HOST_BASE = host_base_1.HOST_BASE; -var instance_1 = __webpack_require__(15); -exports.Instance = instance_1.default; -var logger_1 = __webpack_require__(1); -exports.ConsoleLogger = logger_1.ConsoleLogger; -exports.EmptyLogger = logger_1.EmptyLogger; -var network_1 = __webpack_require__(0); -exports.ErrorResponse = network_1.ErrorResponse; -exports.NetworkError = network_1.NetworkError; -exports.responseToHeadersObject = network_1.responseToHeadersObject; -exports.XhrReadyState = network_1.XhrReadyState; -var request_1 = __webpack_require__(4); -exports.executeNetworkRequest = request_1.executeNetworkRequest; -exports.sendRawRequest = request_1.sendRawRequest; -var resuming_subscription_1 = __webpack_require__(5); -exports.createResumingStrategy = resuming_subscription_1.createResumingStrategy; -var retry_strategy_1 = __webpack_require__(2); -exports.createRetryStrategyOptionsOrDefault = retry_strategy_1.createRetryStrategyOptionsOrDefault; -exports.DoNotRetry = retry_strategy_1.DoNotRetry; -exports.Retry = retry_strategy_1.Retry; -exports.RetryResolution = retry_strategy_1.RetryResolution; -var retrying_subscription_1 = __webpack_require__(6); -exports.createRetryingStrategy = retrying_subscription_1.createRetryingStrategy; -var token_providing_subscription_1 = __webpack_require__(7); -exports.createTokenProvidingStrategy = token_providing_subscription_1.createTokenProvidingStrategy; -var transports_1 = __webpack_require__(8); -exports.createTransportStrategy = transports_1.createTransportStrategy; -exports.default = { - BaseClient: base_client_1.BaseClient, - ConsoleLogger: logger_1.ConsoleLogger, - EmptyLogger: logger_1.EmptyLogger, - Instance: instance_1.default, -}; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.subscribeStrategyListenersFromSubscriptionListeners = function (subListeners) { - return { - onEnd: subListeners.onEnd, - onError: subListeners.onError, - onEvent: subListeners.onEvent, - onOpen: subListeners.onOpen, - onRetrying: subListeners.onRetrying, - }; -}; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -exports.replaceMissingListenersWithNoOps = function (listeners) { - var onEndNoOp = function (error) { }; - var onEnd = listeners.onEnd || onEndNoOp; - var onErrorNoOp = function (error) { }; - var onError = listeners.onError || onErrorNoOp; - var onEventNoOp = function (event) { }; - var onEvent = listeners.onEvent || onEventNoOp; - var onOpenNoOp = function (headers) { }; - var onOpen = listeners.onOpen || onOpenNoOp; - var onRetryingNoOp = function () { }; - var onRetrying = listeners.onRetrying || onRetryingNoOp; - var onSubscribeNoOp = function () { }; - var onSubscribe = listeners.onSubscribe || onSubscribeNoOp; - return { - onEnd: onEnd, - onError: onError, - onEvent: onEvent, - onOpen: onOpen, - onRetrying: onRetrying, - onSubscribe: onSubscribe, - }; -}; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var HttpTransportState; -(function (HttpTransportState) { - HttpTransportState[HttpTransportState["UNOPENED"] = 0] = "UNOPENED"; - HttpTransportState[HttpTransportState["OPENING"] = 1] = "OPENING"; - HttpTransportState[HttpTransportState["OPEN"] = 2] = "OPEN"; - HttpTransportState[HttpTransportState["ENDING"] = 3] = "ENDING"; - HttpTransportState[HttpTransportState["ENDED"] = 4] = "ENDED"; -})(HttpTransportState = exports.HttpTransportState || (exports.HttpTransportState = {})); -var HttpSubscription = (function () { - function HttpSubscription(xhr, listeners) { - var _this = this; - this.gotEOS = false; - this.lastNewlineIndex = 0; - this.state = HttpTransportState.UNOPENED; - this.xhr = xhr; - this.listeners = listeners; - this.xhr.onreadystatechange = function () { - switch (_this.xhr.readyState) { - case network_1.XhrReadyState.UNSENT: - case network_1.XhrReadyState.OPENED: - case network_1.XhrReadyState.HEADERS_RECEIVED: - _this.assertStateIsIn(HttpTransportState.OPENING); - break; - case network_1.XhrReadyState.LOADING: - _this.onLoading(); - break; - case network_1.XhrReadyState.DONE: - _this.onDone(); - break; - } - }; - this.state = HttpTransportState.OPENING; - this.xhr.send(); - return this; - } - HttpSubscription.prototype.unsubscribe = function () { - this.state = HttpTransportState.ENDED; - this.xhr.abort(); - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - }; - HttpSubscription.prototype.onLoading = function () { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDING); - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - window.console.log(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN); - var err = this.onChunk(); - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - if (err) { - this.state = HttpTransportState.ENDED; - if (err instanceof network_1.ErrorResponse && err.statusCode !== 204) { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else { - } - } - }; - HttpSubscription.prototype.onDone = function () { - if (this.xhr.status === 200) { - if (this.state === HttpTransportState.OPENING) { - this.state = HttpTransportState.OPEN; - if (this.listeners.onOpen) { - this.listeners.onOpen(network_1.responseToHeadersObject(this.xhr.getAllResponseHeaders())); - } - } - this.assertStateIsIn(HttpTransportState.OPEN, HttpTransportState.ENDING); - var err = this.onChunk(); - if (err) { - this.state = HttpTransportState.ENDED; - if (err.statusCode === 204) { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(err); - } - } - } - else if (this.state <= HttpTransportState.ENDING) { - if (this.listeners.onError) { - this.listeners.onError(new Error('HTTP response ended without receiving EOS message')); - } - } - else { - if (this.listeners.onEnd) { - this.listeners.onEnd(null); - } - } - } - else { - this.assertStateIsIn(HttpTransportState.OPENING, HttpTransportState.OPEN, HttpTransportState.ENDED); - if (this.state === HttpTransportState.ENDED) { - return; - } - else if (this.xhr.status === 0) { - if (this.listeners.onError) { - this.listeners.onError(new network_1.NetworkError('Connection lost.')); - } - } - else { - if (this.listeners.onError) { - this.listeners.onError(network_1.ErrorResponse.fromXHR(this.xhr)); - } - } - } - }; - HttpSubscription.prototype.onChunk = function () { - this.assertStateIsIn(HttpTransportState.OPEN); - var response = this.xhr.responseText; - var newlineIndex = response.lastIndexOf('\n'); - if (newlineIndex > this.lastNewlineIndex) { - var rawEvents = response - .slice(this.lastNewlineIndex, newlineIndex) - .split('\n'); - this.lastNewlineIndex = newlineIndex; - for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { - var rawEvent = rawEvents_1[_i]; - if (rawEvent.length === 0) { - continue; - } - var data = JSON.parse(rawEvent); - var err = this.onMessage(data); - if (err != null) { - return err; - } - } - } - }; - HttpSubscription.prototype.assertStateIsIn = function () { - var _this = this; - var validStates = []; - for (var _i = 0; _i < arguments.length; _i++) { - validStates[_i] = arguments[_i]; - } - var stateIsValid = validStates.some(function (validState) { return validState === _this.state; }); - if (!stateIsValid) { - var expectedStates = validStates - .map(function (state) { return HttpTransportState[state]; }) - .join(', '); - var actualState = HttpTransportState[this.state]; - window.console.warn("Expected this.state to be one of [" + expectedStates + "] but it is " + actualState); - } - }; - HttpSubscription.prototype.onMessage = function (message) { - this.assertStateIsIn(HttpTransportState.OPEN); - this.verifyMessage(message); - switch (message[0]) { - case 0: - return null; - case 1: - return this.onEventMessage(message); - case 255: - return this.onEOSMessage(message); - default: - return new Error('Unknown Message: ' + JSON.stringify(message)); - } - }; - HttpSubscription.prototype.onEventMessage = function (eventMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eventMessage.length !== 4) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var _ = eventMessage[0], id = eventMessage[1], headers = eventMessage[2], body = eventMessage[3]; - if (typeof id !== 'string') { - return new Error('Invalid event ID in message: ' + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid event headers in message: ' + JSON.stringify(eventMessage)); - } - if (this.listeners.onEvent) { - this.listeners.onEvent({ body: body, headers: headers, eventId: id }); - } - return null; - }; - HttpSubscription.prototype.onEOSMessage = function (eosMessage) { - this.assertStateIsIn(HttpTransportState.OPEN); - if (eosMessage.length !== 4) { - return new Error('EOS message has ' + eosMessage.length + ' elements (expected 4)'); - } - var _ = eosMessage[0], statusCode = eosMessage[1], headers = eosMessage[2], info = eosMessage[3]; - if (typeof statusCode !== 'number') { - return new Error('Invalid EOS Status Code'); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error('Invalid EOS ElementsHeaders'); - } - this.state = HttpTransportState.ENDING; - return new network_1.ErrorResponse(statusCode, headers, info); - }; - HttpSubscription.prototype.verifyMessage = function (message) { - if (this.gotEOS) { - return new Error('Got another message after EOS message'); - } - if (!Array.isArray(message)) { - return new Error('Message is not an array'); - } - if (message.length < 1) { - return new Error('Message is empty array'); - } - }; - return HttpSubscription; -}()); -var HttpTransport = (function () { - function HttpTransport(host, encrypted) { - if (encrypted === void 0) { encrypted = true; } - this.baseURL = (encrypted ? 'https' : 'http') + "://" + host; - } - HttpTransport.prototype.request = function (requestOptions) { - return this.createXHR(this.baseURL, requestOptions); - }; - HttpTransport.prototype.subscribe = function (path, listeners, headers) { - var requestOptions = { - headers: headers, - method: 'SUBSCRIBE', - path: path, - }; - return new HttpSubscription(this.createXHR(this.baseURL, requestOptions), listeners); - }; - HttpTransport.prototype.createXHR = function (baseURL, options) { - var xhr = new window.XMLHttpRequest(); - var path = options.path.replace(/^\/+/, ''); - var endpoint = baseURL + "/" + path; - xhr.open(options.method.toUpperCase(), endpoint, true); - xhr = this.setJSONHeaderIfAppropriate(xhr, options); - if (options.jwt) { - xhr.setRequestHeader('authorization', "Bearer " + options.jwt); - } - if (options.headers) { - for (var key in options.headers) { - if (options.headers.hasOwnProperty(key)) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - } - return xhr; - }; - HttpTransport.prototype.setJSONHeaderIfAppropriate = function (xhr, options) { - if (options.json) { - xhr.setRequestHeader('content-type', 'application/json'); - } - return xhr; - }; - return HttpTransport; -}()); -exports.default = HttpTransport; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var network_1 = __webpack_require__(0); -var SubscribeMessageType = 100; -var OpenMessageType = 101; -var EventMessageType = 102; -var UnsubscribeMessageType = 198; -var EosMessageType = 199; -var PingMessageType = 16; -var PongMessageType = 17; -var CloseMessageType = 99; -var WSReadyState; -(function (WSReadyState) { - WSReadyState[WSReadyState["Connecting"] = 0] = "Connecting"; - WSReadyState[WSReadyState["Open"] = 1] = "Open"; - WSReadyState[WSReadyState["Closing"] = 2] = "Closing"; - WSReadyState[WSReadyState["Closed"] = 3] = "Closed"; -})(WSReadyState = exports.WSReadyState || (exports.WSReadyState = {})); -var WsSubscriptions = (function () { - function WsSubscriptions() { - this.subscriptions = {}; - } - WsSubscriptions.prototype.add = function (subID, path, listeners, headers) { - this.subscriptions[subID] = { - headers: headers, - listeners: listeners, - path: path, - }; - return subID; - }; - WsSubscriptions.prototype.has = function (subID) { - return this.subscriptions[subID] !== undefined; - }; - WsSubscriptions.prototype.isEmpty = function () { - return Object.keys(this.subscriptions).length === 0; - }; - WsSubscriptions.prototype.remove = function (subID) { - return delete this.subscriptions[subID]; - }; - WsSubscriptions.prototype.get = function (subID) { - return this.subscriptions[subID]; - }; - WsSubscriptions.prototype.getAll = function () { - return this.subscriptions; - }; - WsSubscriptions.prototype.getAllAsArray = function () { - var _this = this; - return Object.keys(this.subscriptions).map(function (subID) { return (__assign({ subID: parseInt(subID, 10) }, _this.subscriptions[parseInt(subID, 10)])); }); - }; - WsSubscriptions.prototype.removeAll = function () { - this.subscriptions = {}; - }; - return WsSubscriptions; -}()); -var WsSubscription = (function () { - function WsSubscription(wsTransport, subID) { - this.wsTransport = wsTransport; - this.subID = subID; - } - WsSubscription.prototype.unsubscribe = function () { - this.wsTransport.unsubscribe(this.subID); - }; - return WsSubscription; -}()); -var pingIntervalMs = 30000; -var pingTimeoutMs = 10000; -var WebSocketTransport = (function () { - function WebSocketTransport(host) { - this.webSocketPath = '/ws'; - this.forcedClose = false; - this.closedError = null; - this.baseURL = "wss://" + host + this.webSocketPath; - this.lastSubscriptionID = 0; - this.subscriptions = new WsSubscriptions(); - this.pendingSubscriptions = new WsSubscriptions(); - this.connect(); - } - WebSocketTransport.prototype.subscribe = function (path, listeners, headers) { - this.tryReconnectIfNeeded(); - var subID = this.lastSubscriptionID++; - if (this.socket.readyState !== WSReadyState.Open) { - this.pendingSubscriptions.add(subID, path, listeners, headers); - return new WsSubscription(this, subID); - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - return new WsSubscription(this, subID); - }; - WebSocketTransport.prototype.unsubscribe = function (subID) { - this.sendMessage(this.getMessage(UnsubscribeMessageType, subID)); - var subscription = this.subscriptions.get(subID); - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - this.subscriptions.remove(subID); - }; - WebSocketTransport.prototype.connect = function () { - var _this = this; - this.close(); - this.forcedClose = false; - this.closedError = null; - this.socket = new window.WebSocket(this.baseURL); - this.socket.onopen = function (event) { - var allPendingSubscriptions = _this.pendingSubscriptions.getAllAsArray(); - allPendingSubscriptions.forEach(function (subscription) { - var subID = subscription.subID, path = subscription.path, listeners = subscription.listeners, headers = subscription.headers; - _this.subscribePending(path, listeners, headers, subID); - }); - _this.pendingSubscriptions.removeAll(); - _this.pingInterval = window.setInterval(function () { - if (_this.pongTimeout) { - return; - } - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - return; - } - _this.sendMessage(_this.getMessage(PingMessageType, now)); - _this.lastSentPingID = now; - _this.pongTimeout = window.setTimeout(function () { - var now = new Date().getTime(); - if (pingTimeoutMs > now - _this.lastMessageReceivedTimestamp) { - _this.pongTimeout = null; - return; - } - _this.close(new network_1.NetworkError("Pong response wasn't received until timeout.")); - }, pingTimeoutMs); - }, pingIntervalMs); - }; - this.socket.onmessage = function (event) { return _this.receiveMessage(event); }; - this.socket.onerror = function (event) { - _this.close(new network_1.NetworkError('Connection was lost.')); - }; - this.socket.onclose = function (event) { - if (!_this.forcedClose) { - _this.tryReconnectIfNeeded(); - return; - } - var callback = _this.closedError - ? function (subscription) { - if (subscription.listeners.onError) { - subscription.listeners.onError(_this.closedError); - } - } - : function (subscription) { - if (subscription.listeners.onEnd) { - subscription.listeners.onEnd(null); - } - }; - var allSubscriptions = _this.pendingSubscriptions.isEmpty() === false - ? _this.pendingSubscriptions - : _this.subscriptions; - allSubscriptions.getAllAsArray().forEach(callback); - allSubscriptions.removeAll(); - if (_this.closedError) { - _this.tryReconnectIfNeeded(); - } - }; - }; - WebSocketTransport.prototype.close = function (error) { - if (!(this.socket instanceof window.WebSocket)) { - return; - } - this.forcedClose = true; - this.closedError = error; - this.socket.close(); - window.clearTimeout(this.pingInterval); - window.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.tryReconnectIfNeeded = function () { - if (this.socket.readyState !== WSReadyState.Closed) { - return; - } - this.connect(); - }; - WebSocketTransport.prototype.subscribePending = function (path, listeners, headers, subID) { - if (subID === undefined) { - window.console.logger.debug("Subscription to path " + path + " has an undefined ID"); - return; - } - this.subscriptions.add(subID, path, listeners, headers); - this.sendMessage(this.getMessage(SubscribeMessageType, subID, path, headers)); - }; - WebSocketTransport.prototype.getMessage = function (messageType, id, path, headers) { - return [messageType, id, path, headers]; - }; - WebSocketTransport.prototype.sendMessage = function (message) { - if (this.socket.readyState !== WSReadyState.Open) { - return window.console.warn("Can't send in \"" + WSReadyState[this.socket.readyState] + "\" state"); - } - this.socket.send(JSON.stringify(message)); - }; - WebSocketTransport.prototype.subscription = function (subID) { - return this.subscriptions.get(subID); - }; - WebSocketTransport.prototype.receiveMessage = function (event) { - this.lastMessageReceivedTimestamp = new Date().getTime(); - var message; - try { - message = JSON.parse(event.data); - } - catch (err) { - this.close(new Error("Message is not valid JSON format. Getting " + event.data)); - return; - } - var nonValidMessageError = this.validateMessage(message); - if (nonValidMessageError) { - this.close(new Error(nonValidMessageError.message)); - return; - } - var messageType = message.shift(); - switch (messageType) { - case PongMessageType: - this.onPongMessage(message); - return; - case PingMessageType: - this.onPingMessage(message); - return; - case CloseMessageType: - this.onCloseMessage(message); - return; - } - var subID = message.shift(); - var subscription = this.subscription(subID); - if (!subscription) { - this.close(new Error("Received message for non existing subscription id: \"" + subID + "\"")); - return; - } - var listeners = subscription.listeners; - switch (messageType) { - case OpenMessageType: - this.onOpenMessage(message, subID, listeners); - break; - case EventMessageType: - this.onEventMessage(message, listeners); - break; - case EosMessageType: - this.onEOSMessage(message, subID, listeners); - break; - default: - this.close(new Error('Received non existing type of message.')); - } - }; - WebSocketTransport.prototype.validateMessage = function (message) { - if (!Array.isArray(message)) { - return new Error("Message is expected to be an array. Getting: " + JSON.stringify(message)); - } - if (message.length < 1) { - return new Error("Message is empty array: " + JSON.stringify(message)); - } - return null; - }; - WebSocketTransport.prototype.onOpenMessage = function (message, subID, subscriptionListeners) { - if (subscriptionListeners.onOpen) { - subscriptionListeners.onOpen(message[1]); - } - }; - WebSocketTransport.prototype.onEventMessage = function (eventMessage, subscriptionListeners) { - if (eventMessage.length !== 3) { - return new Error('Event message has ' + eventMessage.length + ' elements (expected 4)'); - } - var eventId = eventMessage[0], headers = eventMessage[1], body = eventMessage[2]; - if (typeof eventId !== 'string') { - return new Error("Invalid event ID in message: " + JSON.stringify(eventMessage)); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return new Error("Invalid event headers in message: " + JSON.stringify(eventMessage)); - } - if (subscriptionListeners.onEvent) { - subscriptionListeners.onEvent({ eventId: eventId, headers: headers, body: body }); - } - }; - WebSocketTransport.prototype.onEOSMessage = function (eosMessage, subID, subscriptionListeners) { - this.subscriptions.remove(subID); - if (eosMessage.length !== 3) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error("EOS message has " + eosMessage.length + " elements (expected 4)")); - } - return; - } - var statusCode = eosMessage[0], headers = eosMessage[1], body = eosMessage[2]; - if (typeof statusCode !== 'number') { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS Status Code')); - } - return; - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new Error('Invalid EOS ElementsHeaders')); - } - return; - } - if (statusCode === 204) { - if (subscriptionListeners.onEnd) { - subscriptionListeners.onEnd(null); - } - return; - } - if (subscriptionListeners.onError) { - subscriptionListeners.onError(new network_1.ErrorResponse(statusCode, headers, body)); - } - return; - }; - WebSocketTransport.prototype.onCloseMessage = function (closeMessage) { - var statusCode = closeMessage[0], headers = closeMessage[1], body = closeMessage[2]; - if (typeof statusCode !== 'number') { - return this.close(new Error('Close message: Invalid EOS Status Code')); - } - if (typeof headers !== 'object' || Array.isArray(headers)) { - return this.close(new Error('Close message: Invalid EOS ElementsHeaders')); - } - this.close(); - }; - WebSocketTransport.prototype.onPongMessage = function (message) { - var receviedPongID = message[0]; - if (this.lastSentPingID !== receviedPongID) { - this.close(new network_1.NetworkError("Didn't received pong with proper ID")); - } - window.clearTimeout(this.pongTimeout); - delete this.pongTimeout; - this.lastSentPingID = null; - }; - WebSocketTransport.prototype.onPingMessage = function (message) { - var receviedPingID = message[0]; - this.sendMessage(this.getMessage(PongMessageType, receviedPingID)); - }; - return WebSocketTransport; -}()); -exports.default = WebSocketTransport; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -Object.defineProperty(exports, "__esModule", { value: true }); -var base_client_1 = __webpack_require__(3); -var host_base_1 = __webpack_require__(9); -var logger_1 = __webpack_require__(1); -var Instance = (function () { - function Instance(options) { - if (!options.locator) { - throw new Error('Expected `locator` property in Instance options!'); - } - var splitInstanceLocator = options.locator.split(':'); - if (splitInstanceLocator.length !== 3) { - throw new Error('The instance locator property is in the wrong format!'); - } - if (!options.serviceName) { - throw new Error('Expected `serviceName` property in Instance options!'); - } - if (!options.serviceVersion) { - throw new Error('Expected `serviceVersion` property in Instance otpions!'); - } - this.platformVersion = splitInstanceLocator[0]; - this.cluster = splitInstanceLocator[1]; - this.id = splitInstanceLocator[2]; - this.serviceName = options.serviceName; - this.serviceVersion = options.serviceVersion; - this.host = options.host || this.cluster + "." + host_base_1.HOST_BASE; - this.logger = options.logger || new logger_1.ConsoleLogger(); - this.client = - options.client || - new base_client_1.BaseClient({ - encrypted: options.encrypted, - host: this.host, - logger: this.logger, - }); - this.tokenProvider = options.tokenProvider; - } - Instance.prototype.request = function (options, tokenParams) { - options.path = this.absPath(options.path); - if (options.headers == null || options.headers === undefined) { - options.headers = {}; - } - options.tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.request(options, tokenParams); - }; - Instance.prototype.subscribeNonResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeNonResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, tokenProvider); - }; - Instance.prototype.subscribeResuming = function (options) { - var headers = options.headers || {}; - var retryStrategyOptions = options.retryStrategyOptions || {}; - var tokenProvider = options.tokenProvider || this.tokenProvider; - return this.client.subscribeResuming(this.absPath(options.path), headers, options.listeners, retryStrategyOptions, options.initialEventId, tokenProvider); - }; - Instance.prototype.absPath = function (relativePath) { - return ("/services/" + this.serviceName + "/" + this.serviceVersion + "/" + this.id + "/" + relativePath) - .replace(/\/+/g, '/') - .replace(/\/+$/, ''); - }; - return Instance; -}()); -exports.default = Instance; - - -/***/ }) -/******/ ]); -}); -}); - -unwrapExports(pusherPlatform); -var pusherPlatform_1 = pusherPlatform.BaseClient; -var pusherPlatform_2 = pusherPlatform.HOST_BASE; -var pusherPlatform_3 = pusherPlatform.Instance; -var pusherPlatform_4 = pusherPlatform.sendRawRequest; - -function _isPlaceholder(a) { - return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true; -} - -/** - * Optimized internal one-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry1(fn) { - return function f1(a) { - if (arguments.length === 0 || _isPlaceholder(a)) { - return f1; - } else { - return fn.apply(this, arguments); - } - }; -} - -/** - * Returns a function that always returns the given value. Note that for - * non-primitives the value returned is a reference to the original value. - * - * This function is known as `const`, `constant`, or `K` (for K combinator) in - * other languages and libraries. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig a -> (* -> a) - * @param {*} val The value to wrap in a function - * @return {Function} A Function :: * -> val. - * @example - * - * var t = R.always('Tee'); - * t(); //=> 'Tee' - */ -var always = /*#__PURE__*/_curry1(function always(val) { - return function () { - return val; - }; -}); - -/** - * A function that always returns `false`. Any passed in parameters are ignored. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig * -> Boolean - * @param {*} - * @return {Boolean} - * @see R.always, R.T - * @example - * - * R.F(); //=> false - */ -var F = /*#__PURE__*/always(false); - -/** - * A function that always returns `true`. Any passed in parameters are ignored. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig * -> Boolean - * @param {*} - * @return {Boolean} - * @see R.always, R.F - * @example - * - * R.T(); //=> true - */ -var T = /*#__PURE__*/always(true); - -/** - * A special placeholder value used to specify "gaps" within curried functions, - * allowing partial application of any combination of arguments, regardless of - * their positions. - * - * If `g` is a curried ternary function and `_` is `R.__`, the following are - * equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2, _)(1, 3)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @constant - * @memberOf R - * @since v0.6.0 - * @category Function - * @example - * - * var greet = R.replace('{name}', R.__, 'Hello, {name}!'); - * greet('Alice'); //=> 'Hello, Alice!' - */ - -/** - * Optimized internal two-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry2(fn) { - return function f2(a, b) { - switch (arguments.length) { - case 0: - return f2; - case 1: - return _isPlaceholder(a) ? f2 : _curry1(function (_b) { - return fn(a, _b); - }); - default: - return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) { - return fn(_a, b); - }) : _isPlaceholder(b) ? _curry1(function (_b) { - return fn(a, _b); - }) : fn(a, b); - } - }; -} - -/** - * Adds two values. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig Number -> Number -> Number - * @param {Number} a - * @param {Number} b - * @return {Number} - * @see R.subtract - * @example - * - * R.add(2, 3); //=> 5 - * R.add(7)(10); //=> 17 - */ -var add = /*#__PURE__*/_curry2(function add(a, b) { - return Number(a) + Number(b); -}); - -/** - * Private `concat` function to merge two array-like objects. - * - * @private - * @param {Array|Arguments} [set1=[]] An array-like object. - * @param {Array|Arguments} [set2=[]] An array-like object. - * @return {Array} A new, merged array. - * @example - * - * _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] - */ -function _concat(set1, set2) { - set1 = set1 || []; - set2 = set2 || []; - var idx; - var len1 = set1.length; - var len2 = set2.length; - var result = []; - - idx = 0; - while (idx < len1) { - result[result.length] = set1[idx]; - idx += 1; - } - idx = 0; - while (idx < len2) { - result[result.length] = set2[idx]; - idx += 1; - } - return result; -} - -function _arity(n, fn) { - /* eslint-disable no-unused-vars */ - switch (n) { - case 0: - return function () { - return fn.apply(this, arguments); - }; - case 1: - return function (a0) { - return fn.apply(this, arguments); - }; - case 2: - return function (a0, a1) { - return fn.apply(this, arguments); - }; - case 3: - return function (a0, a1, a2) { - return fn.apply(this, arguments); - }; - case 4: - return function (a0, a1, a2, a3) { - return fn.apply(this, arguments); - }; - case 5: - return function (a0, a1, a2, a3, a4) { - return fn.apply(this, arguments); - }; - case 6: - return function (a0, a1, a2, a3, a4, a5) { - return fn.apply(this, arguments); - }; - case 7: - return function (a0, a1, a2, a3, a4, a5, a6) { - return fn.apply(this, arguments); - }; - case 8: - return function (a0, a1, a2, a3, a4, a5, a6, a7) { - return fn.apply(this, arguments); - }; - case 9: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { - return fn.apply(this, arguments); - }; - case 10: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { - return fn.apply(this, arguments); - }; - default: - throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); - } -} - -/** - * Internal curryN function. - * - * @private - * @category Function - * @param {Number} length The arity of the curried function. - * @param {Array} received An array of arguments received thus far. - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curryN(length, received, fn) { - return function () { - var combined = []; - var argsIdx = 0; - var left = length; - var combinedIdx = 0; - while (combinedIdx < received.length || argsIdx < arguments.length) { - var result; - if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) { - result = received[combinedIdx]; - } else { - result = arguments[argsIdx]; - argsIdx += 1; - } - combined[combinedIdx] = result; - if (!_isPlaceholder(result)) { - left -= 1; - } - combinedIdx += 1; - } - return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn)); - }; -} - -/** - * Returns a curried equivalent of the provided function, with the specified - * arity. The curried function has two unusual capabilities. First, its - * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the - * following are equivalent: - * - * - `g(1)(2)(3)` - * - `g(1)(2, 3)` - * - `g(1, 2)(3)` - * - `g(1, 2, 3)` - * - * Secondly, the special placeholder value [`R.__`](#__) may be used to specify - * "gaps", allowing partial application of any combination of arguments, - * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), - * the following are equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @func - * @memberOf R - * @since v0.5.0 - * @category Function - * @sig Number -> (* -> a) -> (* -> a) - * @param {Number} length The arity for the returned function. - * @param {Function} fn The function to curry. - * @return {Function} A new, curried function. - * @see R.curry - * @example - * - * var sumArgs = (...args) => R.sum(args); - * - * var curriedAddFourNumbers = R.curryN(4, sumArgs); - * var f = curriedAddFourNumbers(1, 2); - * var g = f(3); - * g(4); //=> 10 - */ -var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) { - if (length === 1) { - return _curry1(fn); - } - return _arity(length, _curryN(length, [], fn)); -}); - -/** - * Optimized internal three-arity curry function. - * - * @private - * @category Function - * @param {Function} fn The function to curry. - * @return {Function} The curried function. - */ -function _curry3(fn) { - return function f3(a, b, c) { - switch (arguments.length) { - case 0: - return f3; - case 1: - return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) { - return fn(a, _b, _c); - }); - case 2: - return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) { - return fn(_a, b, _c); - }) : _isPlaceholder(b) ? _curry2(function (_b, _c) { - return fn(a, _b, _c); - }) : _curry1(function (_c) { - return fn(a, b, _c); - }); - default: - return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) { - return fn(_a, _b, c); - }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) { - return fn(_a, b, _c); - }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) { - return fn(a, _b, _c); - }) : _isPlaceholder(a) ? _curry1(function (_a) { - return fn(_a, b, c); - }) : _isPlaceholder(b) ? _curry1(function (_b) { - return fn(a, _b, c); - }) : _isPlaceholder(c) ? _curry1(function (_c) { - return fn(a, b, _c); - }) : fn(a, b, c); - } - }; -} - -/** - * Tests whether or not an object is an array. - * - * @private - * @param {*} val The object to test. - * @return {Boolean} `true` if `val` is an array, `false` otherwise. - * @example - * - * _isArray([]); //=> true - * _isArray(null); //=> false - * _isArray({}); //=> false - */ -var _isArray = Array.isArray || function _isArray(val) { - return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]'; -}; - -function _isTransformer(obj) { - return typeof obj['@@transducer/step'] === 'function'; -} - -/** - * Returns a function that dispatches with different strategies based on the - * object in list position (last argument). If it is an array, executes [fn]. - * Otherwise, if it has a function with one of the given method names, it will - * execute that function (functor case). Otherwise, if it is a transformer, - * uses transducer [xf] to return a new transformer (transducer case). - * Otherwise, it will default to executing [fn]. - * - * @private - * @param {Array} methodNames properties to check for a custom implementation - * @param {Function} xf transducer to initialize if object is transformer - * @param {Function} fn default ramda implementation - * @return {Function} A function that dispatches on object in list position - */ -function _dispatchable(methodNames, xf, fn) { - return function () { - if (arguments.length === 0) { - return fn(); - } - var args = Array.prototype.slice.call(arguments, 0); - var obj = args.pop(); - if (!_isArray(obj)) { - var idx = 0; - while (idx < methodNames.length) { - if (typeof obj[methodNames[idx]] === 'function') { - return obj[methodNames[idx]].apply(obj, args); - } - idx += 1; - } - if (_isTransformer(obj)) { - var transducer = xf.apply(null, args); - return transducer(obj); - } - } - return fn.apply(this, arguments); - }; -} - -var _xfBase = { - init: function () { - return this.xf['@@transducer/init'](); - }, - result: function (result) { - return this.xf['@@transducer/result'](result); - } -}; - -/** - * Returns the larger of its two arguments. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig Ord a => a -> a -> a - * @param {*} a - * @param {*} b - * @return {*} - * @see R.maxBy, R.min - * @example - * - * R.max(789, 123); //=> 789 - * R.max('a', 'b'); //=> 'b' - */ -var max = /*#__PURE__*/_curry2(function max(a, b) { - return b > a ? b : a; -}); - -function _map(fn, functor) { - var idx = 0; - var len = functor.length; - var result = Array(len); - while (idx < len) { - result[idx] = fn(functor[idx]); - idx += 1; - } - return result; -} - -function _isString(x) { - return Object.prototype.toString.call(x) === '[object String]'; -} - -/** - * Tests whether or not an object is similar to an array. - * - * @private - * @category Type - * @category List - * @sig * -> Boolean - * @param {*} x The object to test. - * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise. - * @example - * - * _isArrayLike([]); //=> true - * _isArrayLike(true); //=> false - * _isArrayLike({}); //=> false - * _isArrayLike({length: 10}); //=> false - * _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true - */ -var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) { - if (_isArray(x)) { - return true; - } - if (!x) { - return false; - } - if (typeof x !== 'object') { - return false; - } - if (_isString(x)) { - return false; - } - if (x.nodeType === 1) { - return !!x.length; - } - if (x.length === 0) { - return true; - } - if (x.length > 0) { - return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1); - } - return false; -}); - -var XWrap = /*#__PURE__*/function () { - function XWrap(fn) { - this.f = fn; - } - XWrap.prototype['@@transducer/init'] = function () { - throw new Error('init not implemented on XWrap'); - }; - XWrap.prototype['@@transducer/result'] = function (acc) { - return acc; - }; - XWrap.prototype['@@transducer/step'] = function (acc, x) { - return this.f(acc, x); - }; - - return XWrap; -}(); - -function _xwrap(fn) { - return new XWrap(fn); -} - -/** - * Creates a function that is bound to a context. - * Note: `R.bind` does not provide the additional argument-binding capabilities of - * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). - * - * @func - * @memberOf R - * @since v0.6.0 - * @category Function - * @category Object - * @sig (* -> *) -> {*} -> (* -> *) - * @param {Function} fn The function to bind to context - * @param {Object} thisObj The context to bind `fn` to - * @return {Function} A function that will execute in the context of `thisObj`. - * @see R.partial - * @example - * - * var log = R.bind(console.log, console); - * R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3} - * // logs {a: 2} - * @symb R.bind(f, o)(a, b) = f.call(o, a, b) - */ -var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) { - return _arity(fn.length, function () { - return fn.apply(thisObj, arguments); - }); -}); - -function _arrayReduce(xf, acc, list) { - var idx = 0; - var len = list.length; - while (idx < len) { - acc = xf['@@transducer/step'](acc, list[idx]); - if (acc && acc['@@transducer/reduced']) { - acc = acc['@@transducer/value']; - break; - } - idx += 1; - } - return xf['@@transducer/result'](acc); -} - -function _iterableReduce(xf, acc, iter) { - var step = iter.next(); - while (!step.done) { - acc = xf['@@transducer/step'](acc, step.value); - if (acc && acc['@@transducer/reduced']) { - acc = acc['@@transducer/value']; - break; - } - step = iter.next(); - } - return xf['@@transducer/result'](acc); -} - -function _methodReduce(xf, acc, obj, methodName) { - return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc)); -} - -var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator'; - -function _reduce(fn, acc, list) { - if (typeof fn === 'function') { - fn = _xwrap(fn); - } - if (_isArrayLike(list)) { - return _arrayReduce(fn, acc, list); - } - if (typeof list['fantasy-land/reduce'] === 'function') { - return _methodReduce(fn, acc, list, 'fantasy-land/reduce'); - } - if (list[symIterator] != null) { - return _iterableReduce(fn, acc, list[symIterator]()); - } - if (typeof list.next === 'function') { - return _iterableReduce(fn, acc, list); - } - if (typeof list.reduce === 'function') { - return _methodReduce(fn, acc, list, 'reduce'); - } - - throw new TypeError('reduce: list must be array or iterable'); -} - -var XMap = /*#__PURE__*/function () { - function XMap(f, xf) { - this.xf = xf; - this.f = f; - } - XMap.prototype['@@transducer/init'] = _xfBase.init; - XMap.prototype['@@transducer/result'] = _xfBase.result; - XMap.prototype['@@transducer/step'] = function (result, input) { - return this.xf['@@transducer/step'](result, this.f(input)); - }; - - return XMap; -}(); - -var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) { - return new XMap(f, xf); -}); - -function _has(prop, obj) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -var toString = Object.prototype.toString; -var _isArguments = function () { - return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) { - return toString.call(x) === '[object Arguments]'; - } : function _isArguments(x) { - return _has('callee', x); - }; -}; - -// cover IE < 9 keys issues -var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString'); -var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; -// Safari bug -var hasArgsEnumBug = /*#__PURE__*/function () { - return arguments.propertyIsEnumerable('length'); -}(); - -var contains = function contains(list, item) { - var idx = 0; - while (idx < list.length) { - if (list[idx] === item) { - return true; - } - idx += 1; - } - return false; -}; - -/** - * Returns a list containing the names of all the enumerable own properties of - * the supplied object. - * Note that the order of the output array is not guaranteed to be consistent - * across different JS platforms. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {k: v} -> [k] - * @param {Object} obj The object to extract properties from - * @return {Array} An array of the object's own properties. - * @see R.keysIn, R.values - * @example - * - * R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c'] - */ -var _keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? function keys(obj) { - return Object(obj) !== obj ? [] : Object.keys(obj); -} : function keys(obj) { - if (Object(obj) !== obj) { - return []; - } - var prop, nIdx; - var ks = []; - var checkArgsLength = hasArgsEnumBug && _isArguments(obj); - for (prop in obj) { - if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) { - ks[ks.length] = prop; - } - } - if (hasEnumBug) { - nIdx = nonEnumerableProps.length - 1; - while (nIdx >= 0) { - prop = nonEnumerableProps[nIdx]; - if (_has(prop, obj) && !contains(ks, prop)) { - ks[ks.length] = prop; - } - nIdx -= 1; - } - } - return ks; -}; -var keys = /*#__PURE__*/_curry1(_keys); - -/** - * Takes a function and - * a [functor](https://github.com/fantasyland/fantasy-land#functor), - * applies the function to each of the functor's values, and returns - * a functor of the same shape. - * - * Ramda provides suitable `map` implementations for `Array` and `Object`, - * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`. - * - * Dispatches to the `map` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * Also treats functions as functors and will compose them together. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Functor f => (a -> b) -> f a -> f b - * @param {Function} fn The function to be called on every element of the input `list`. - * @param {Array} list The list to be iterated over. - * @return {Array} The new list. - * @see R.transduce, R.addIndex - * @example - * - * var double = x => x * 2; - * - * R.map(double, [1, 2, 3]); //=> [2, 4, 6] - * - * R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6} - * @symb R.map(f, [a, b]) = [f(a), f(b)] - * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) } - * @symb R.map(f, functor_o) = functor_o.map(f) - */ -var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) { - switch (Object.prototype.toString.call(functor)) { - case '[object Function]': - return curryN(functor.length, function () { - return fn.call(this, functor.apply(this, arguments)); - }); - case '[object Object]': - return _reduce(function (acc, key) { - acc[key] = fn(functor[key]); - return acc; - }, {}, keys(functor)); - default: - return _map(fn, functor); - } -})); - -/** - * Retrieve the value at a given path. - * - * @func - * @memberOf R - * @since v0.2.0 - * @category Object - * @typedefn Idx = String | Int - * @sig [Idx] -> {a} -> a | Undefined - * @param {Array} path The path to use. - * @param {Object} obj The object to retrieve the nested property from. - * @return {*} The data at `path`. - * @see R.prop - * @example - * - * R.path(['a', 'b'], {a: {b: 2}}); //=> 2 - * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined - */ -var path = /*#__PURE__*/_curry2(function path(paths, obj) { - var val = obj; - var idx = 0; - while (idx < paths.length) { - if (val == null) { - return; - } - val = val[paths[idx]]; - idx += 1; - } - return val; -}); - -/** - * Returns a function that when supplied an object returns the indicated - * property of that object, if it exists. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig s -> {s: a} -> a | Undefined - * @param {String} p The property name - * @param {Object} obj The object to query - * @return {*} The value at `obj.p`. - * @see R.path - * @example - * - * R.prop('x', {x: 100}); //=> 100 - * R.prop('x', {}); //=> undefined - */ - -var prop = /*#__PURE__*/_curry2(function prop(p, obj) { - return path([p], obj); -}); - -/** - * Returns a new list by plucking the same named property off all objects in - * the list supplied. - * - * `pluck` will work on - * any [functor](https://github.com/fantasyland/fantasy-land#functor) in - * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Functor f => k -> f {k: v} -> f v - * @param {Number|String} key The key name to pluck off of each object. - * @param {Array} f The array or functor to consider. - * @return {Array} The list of values for the given key. - * @see R.props - * @example - * - * R.pluck('a')([{a: 1}, {a: 2}]); //=> [1, 2] - * R.pluck(0)([[1, 2], [3, 4]]); //=> [1, 3] - * R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5} - * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5] - * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5] - */ -var pluck = /*#__PURE__*/_curry2(function pluck(p, list) { - return map(prop(p), list); -}); - -/** - * Returns a single item by iterating through the list, successively calling - * the iterator function and passing it an accumulator value and the current - * value from the array, and then passing the result to the next call. - * - * The iterator function receives two values: *(acc, value)*. It may use - * [`R.reduced`](#reduced) to shortcut the iteration. - * - * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function - * is *(value, acc)*. - * - * Note: `R.reduce` does not skip deleted or unassigned indices (sparse - * arrays), unlike the native `Array.prototype.reduce` method. For more details - * on this behavior, see: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description - * - * Dispatches to the `reduce` method of the third argument, if present. When - * doing so, it is up to the user to handle the [`R.reduced`](#reduced) - * shortcuting, as this is not implemented by `reduce`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig ((a, b) -> a) -> a -> [b] -> a - * @param {Function} fn The iterator function. Receives two values, the accumulator and the - * current element from the array. - * @param {*} acc The accumulator value. - * @param {Array} list The list to iterate over. - * @return {*} The final, accumulated value. - * @see R.reduced, R.addIndex, R.reduceRight - * @example - * - * R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10 - * // - -10 - * // / \ / \ - * // - 4 -6 4 - * // / \ / \ - * // - 3 ==> -3 3 - * // / \ / \ - * // - 2 -1 2 - * // / \ / \ - * // 0 1 0 1 - * - * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d) - */ -var reduce = /*#__PURE__*/_curry3(_reduce); - -/** - * ap applies a list of functions to a list of values. - * - * Dispatches to the `ap` method of the second argument, if present. Also - * treats curried functions as applicatives. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category Function - * @sig [a -> b] -> [a] -> [b] - * @sig Apply f => f (a -> b) -> f a -> f b - * @sig (a -> b -> c) -> (a -> b) -> (a -> c) - * @param {*} applyF - * @param {*} applyX - * @return {*} - * @example - * - * R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6] - * R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"] - * - * // R.ap can also be used as S combinator - * // when only two functions are passed - * R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA' - * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)] - */ -var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) { - return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) { - return applyF(x)(applyX(x)); - } : - // else - _reduce(function (acc, f) { - return _concat(acc, map(f, applyX)); - }, [], applyF); -}); - -/** - * Returns a new list containing the contents of the given list, followed by - * the given element. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig a -> [a] -> [a] - * @param {*} el The element to add to the end of the new list. - * @param {Array} list The list of elements to add a new item to. - * list. - * @return {Array} A new list containing the elements of the old list followed by `el`. - * @see R.prepend - * @example - * - * R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests'] - * R.append('tests', []); //=> ['tests'] - * R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']] - */ -var append = /*#__PURE__*/_curry2(function append(el, list) { - return _concat(list, [el]); -}); - -/** - * Returns a list of all the enumerable own properties of the supplied object. - * Note that the order of the output array is not guaranteed across different - * JS platforms. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {k: v} -> [v] - * @param {Object} obj The object to extract values from - * @return {Array} An array of the values of the object's own properties. - * @see R.valuesIn, R.keys - * @example - * - * R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3] - */ -var values = /*#__PURE__*/_curry1(function values(obj) { - var props = keys(obj); - var len = props.length; - var vals = []; - var idx = 0; - while (idx < len) { - vals[idx] = obj[props[idx]]; - idx += 1; - } - return vals; -}); - -/** - * Determine if the passed argument is an integer. - * - * @private - * @param {*} n - * @category Type - * @return {Boolean} - */ - -function _isFunction(x) { - return Object.prototype.toString.call(x) === '[object Function]'; -} - -/** - * "lifts" a function to be the specified arity, so that it may "map over" that - * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). - * - * @func - * @memberOf R - * @since v0.7.0 - * @category Function - * @sig Number -> (*... -> *) -> ([*]... -> [*]) - * @param {Function} fn The function to lift into higher context - * @return {Function} The lifted function. - * @see R.lift, R.ap - * @example - * - * var madd3 = R.liftN(3, (...args) => R.sum(args)); - * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] - */ -var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) { - var lifted = curryN(arity, fn); - return curryN(arity, function () { - return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1)); - }); -}); - -/** - * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other - * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply). - * - * @func - * @memberOf R - * @since v0.7.0 - * @category Function - * @sig (*... -> *) -> ([*]... -> [*]) - * @param {Function} fn The function to lift into higher context - * @return {Function} The lifted function. - * @see R.liftN - * @example - * - * var madd3 = R.lift((a, b, c) => a + b + c); - * - * madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7] - * - * var madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e); - * - * madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24] - */ -var lift = /*#__PURE__*/_curry1(function lift(fn) { - return liftN(fn.length, fn); -}); - -/** - * Returns a curried equivalent of the provided function. The curried function - * has two unusual capabilities. First, its arguments needn't be provided one - * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the - * following are equivalent: - * - * - `g(1)(2)(3)` - * - `g(1)(2, 3)` - * - `g(1, 2)(3)` - * - `g(1, 2, 3)` - * - * Secondly, the special placeholder value [`R.__`](#__) may be used to specify - * "gaps", allowing partial application of any combination of arguments, - * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__), - * the following are equivalent: - * - * - `g(1, 2, 3)` - * - `g(_, 2, 3)(1)` - * - `g(_, _, 3)(1)(2)` - * - `g(_, _, 3)(1, 2)` - * - `g(_, 2)(1)(3)` - * - `g(_, 2)(1, 3)` - * - `g(_, 2)(_, 3)(1)` - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (* -> a) -> (* -> a) - * @param {Function} fn The function to curry. - * @return {Function} A new, curried function. - * @see R.curryN - * @example - * - * var addFourNumbers = (a, b, c, d) => a + b + c + d; - * - * var curriedAddFourNumbers = R.curry(addFourNumbers); - * var f = curriedAddFourNumbers(1, 2); - * var g = f(3); - * g(4); //=> 10 - */ -var curry = /*#__PURE__*/_curry1(function curry(fn) { - return curryN(fn.length, fn); -}); - -/** - * Returns the result of calling its first argument with the remaining - * arguments. This is occasionally useful as a converging function for - * [`R.converge`](#converge): the first branch can produce a function while the - * remaining branches produce values to be passed to that function as its - * arguments. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Function - * @sig (*... -> a),*... -> a - * @param {Function} fn The function to apply to the remaining arguments. - * @param {...*} args Any number of positional arguments. - * @return {*} - * @see R.apply - * @example - * - * R.call(R.add, 1, 2); //=> 3 - * - * var indentN = R.pipe(R.repeat(' '), - * R.join(''), - * R.replace(/^(?!$)/gm)); - * - * var format = R.converge(R.call, [ - * R.pipe(R.prop('indent'), indentN), - * R.prop('value') - * ]); - * - * format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> ' foo\n bar\n baz\n' - * @symb R.call(f, a, b) = f(a, b) - */ -var call = /*#__PURE__*/curry(function call(fn) { - return fn.apply(this, Array.prototype.slice.call(arguments, 1)); -}); - -/** - * `_makeFlat` is a helper function that returns a one-level or fully recursive - * function based on the flag passed in. - * - * @private - */ -function _makeFlat(recursive) { - return function flatt(list) { - var value, jlen, j; - var result = []; - var idx = 0; - var ilen = list.length; - - while (idx < ilen) { - if (_isArrayLike(list[idx])) { - value = recursive ? flatt(list[idx]) : list[idx]; - j = 0; - jlen = value.length; - while (j < jlen) { - result[result.length] = value[j]; - j += 1; - } - } else { - result[result.length] = list[idx]; - } - idx += 1; - } - return result; - }; -} - -function _forceReduced(x) { - return { - '@@transducer/value': x, - '@@transducer/reduced': true - }; -} - -var preservingReduced = function (xf) { - return { - '@@transducer/init': _xfBase.init, - '@@transducer/result': function (result) { - return xf['@@transducer/result'](result); - }, - '@@transducer/step': function (result, input) { - var ret = xf['@@transducer/step'](result, input); - return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret; - } - }; -}; - -var _flatCat = function _xcat(xf) { - var rxf = preservingReduced(xf); - return { - '@@transducer/init': _xfBase.init, - '@@transducer/result': function (result) { - return rxf['@@transducer/result'](result); - }, - '@@transducer/step': function (result, input) { - return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input); - } - }; -}; - -var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) { - return map(f, _flatCat(xf)); -}); - -/** - * `chain` maps a function over a list and concatenates the results. `chain` - * is also known as `flatMap` in some libraries - * - * Dispatches to the `chain` method of the second argument, if present, - * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain). - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig Chain m => (a -> m b) -> m a -> m b - * @param {Function} fn The function to map with - * @param {Array} list The list to map over - * @return {Array} The result of flat-mapping `list` with `fn` - * @example - * - * var duplicate = n => [n, n]; - * R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3] - * - * R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1] - */ -var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { - if (typeof monad === 'function') { - return function (x) { - return fn(monad(x))(x); - }; - } - return _makeFlat(false)(map(fn, monad)); -})); - -function _cloneRegExp(pattern) { - return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : '')); -} - -/** - * Gives a single-word string description of the (native) type of a value, - * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not - * attempt to distinguish user Object types any further, reporting them all as - * 'Object'. - * - * @func - * @memberOf R - * @since v0.8.0 - * @category Type - * @sig (* -> {*}) -> String - * @param {*} val The value to test - * @return {String} - * @example - * - * R.type({}); //=> "Object" - * R.type(1); //=> "Number" - * R.type(false); //=> "Boolean" - * R.type('s'); //=> "String" - * R.type(null); //=> "Null" - * R.type([]); //=> "Array" - * R.type(/[A-z]/); //=> "RegExp" - * R.type(() => {}); //=> "Function" - * R.type(undefined); //=> "Undefined" - */ -var type = /*#__PURE__*/_curry1(function type(val) { - return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1); -}); - -/** - * Copies an object. - * - * @private - * @param {*} value The value to be copied - * @param {Array} refFrom Array containing the source references - * @param {Array} refTo Array containing the copied source references - * @param {Boolean} deep Whether or not to perform deep cloning. - * @return {*} The copied value. - */ -function _clone(value, refFrom, refTo, deep) { - var copy = function copy(copiedValue) { - var len = refFrom.length; - var idx = 0; - while (idx < len) { - if (value === refFrom[idx]) { - return refTo[idx]; - } - idx += 1; - } - refFrom[idx + 1] = value; - refTo[idx + 1] = copiedValue; - for (var key in value) { - copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key]; - } - return copiedValue; - }; - switch (type(value)) { - case 'Object': - return copy({}); - case 'Array': - return copy([]); - case 'Date': - return new Date(value.valueOf()); - case 'RegExp': - return _cloneRegExp(value); - default: - return value; - } -} - -/** - * Creates a deep copy of the value which may contain (nested) `Array`s and - * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are - * assigned by reference rather than copied - * - * Dispatches to a `clone` method if present. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig {*} -> {*} - * @param {*} value The object or array to clone - * @return {*} A deeply cloned copy of `val` - * @example - * - * var objects = [{}, {}, {}]; - * var objectsClone = R.clone(objects); - * objects === objectsClone; //=> false - * objects[0] === objectsClone[0]; //=> false - */ -var clone = /*#__PURE__*/_curry1(function clone(value) { - return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true); -}); - -/** - * A function that returns the `!` of its argument. It will return `true` when - * passed false-y value, and `false` when passed a truth-y one. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Logic - * @sig * -> Boolean - * @param {*} a any value - * @return {Boolean} the logical inverse of passed argument. - * @see R.complement - * @example - * - * R.not(true); //=> false - * R.not(false); //=> true - * R.not(0); //=> true - * R.not(1); //=> false - */ -var not = /*#__PURE__*/_curry1(function not(a) { - return !a; -}); - -/** - * Takes a function `f` and returns a function `g` such that if called with the same arguments - * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`. - * - * `R.complement` may be applied to any functor - * - * @func - * @memberOf R - * @since v0.12.0 - * @category Logic - * @sig (*... -> *) -> (*... -> Boolean) - * @param {Function} f - * @return {Function} - * @see R.not - * @example - * - * var isNotNil = R.complement(R.isNil); - * isNil(null); //=> true - * isNotNil(null); //=> false - * isNil(7); //=> false - * isNotNil(7); //=> true - */ -var complement = /*#__PURE__*/lift(not); - -function _pipe(f, g) { - return function () { - return g.call(this, f.apply(this, arguments)); - }; -} - -/** - * This checks whether a function has a [methodname] function. If it isn't an - * array it will execute that function otherwise it will default to the ramda - * implementation. - * - * @private - * @param {Function} fn ramda implemtation - * @param {String} methodname property to check for a custom implementation - * @return {Object} Whatever the return value of the method is. - */ -function _checkForMethod(methodname, fn) { - return function () { - var length = arguments.length; - if (length === 0) { - return fn(); - } - var obj = arguments[length - 1]; - return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1)); - }; -} - -/** - * Returns the elements of the given list or string (or object with a `slice` - * method) from `fromIndex` (inclusive) to `toIndex` (exclusive). - * - * Dispatches to the `slice` method of the third argument, if present. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig Number -> Number -> [a] -> [a] - * @sig Number -> Number -> String -> String - * @param {Number} fromIndex The start index (inclusive). - * @param {Number} toIndex The end index (exclusive). - * @param {*} list - * @return {*} - * @example - * - * R.slice(1, 3, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] - * R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd'] - * R.slice(0, -1, ['a', 'b', 'c', 'd']); //=> ['a', 'b', 'c'] - * R.slice(-3, -1, ['a', 'b', 'c', 'd']); //=> ['b', 'c'] - * R.slice(0, 3, 'ramda'); //=> 'ram' - */ -var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) { - return Array.prototype.slice.call(list, fromIndex, toIndex); -})); - -/** - * Returns all but the first element of the given list or string (or object - * with a `tail` method). - * - * Dispatches to the `slice` method of the first argument, if present. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.head, R.init, R.last - * @example - * - * R.tail([1, 2, 3]); //=> [2, 3] - * R.tail([1, 2]); //=> [2] - * R.tail([1]); //=> [] - * R.tail([]); //=> [] - * - * R.tail('abc'); //=> 'bc' - * R.tail('ab'); //=> 'b' - * R.tail('a'); //=> '' - * R.tail(''); //=> '' - */ -var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity))); - -/** - * Performs left-to-right function composition. The leftmost function may have - * any arity; the remaining functions must be unary. - * - * In some libraries this function is named `sequence`. - * - * **Note:** The result of pipe is not automatically curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z) - * @param {...Function} functions - * @return {Function} - * @see R.compose - * @example - * - * var f = R.pipe(Math.pow, R.negate, R.inc); - * - * f(3, 4); // -(3^4) + 1 - * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b))) - */ -function pipe() { - if (arguments.length === 0) { - throw new Error('pipe requires at least one argument'); - } - return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments))); -} - -/** - * Returns a new list or string with the elements or characters in reverse - * order. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {Array|String} list - * @return {Array|String} - * @example - * - * R.reverse([1, 2, 3]); //=> [3, 2, 1] - * R.reverse([1, 2]); //=> [2, 1] - * R.reverse([1]); //=> [1] - * R.reverse([]); //=> [] - * - * R.reverse('abc'); //=> 'cba' - * R.reverse('ab'); //=> 'ba' - * R.reverse('a'); //=> 'a' - * R.reverse(''); //=> '' - */ -var reverse = /*#__PURE__*/_curry1(function reverse(list) { - return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse(); -}); - -/** - * Performs right-to-left function composition. The rightmost function may have - * any arity; the remaining functions must be unary. - * - * **Note:** The result of compose is not automatically curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z) - * @param {...Function} ...functions The functions to compose - * @return {Function} - * @see R.pipe - * @example - * - * var classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName - * var yellGreeting = R.compose(R.toUpper, classyGreeting); - * yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND" - * - * R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7 - * - * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b))) - */ -function compose() { - if (arguments.length === 0) { - throw new Error('compose requires at least one argument'); - } - return pipe.apply(this, reverse(arguments)); -} - -function _arrayFromIterator(iter) { - var list = []; - var next; - while (!(next = iter.next()).done) { - list.push(next.value); - } - return list; -} - -function _containsWith(pred, x, list) { - var idx = 0; - var len = list.length; - - while (idx < len) { - if (pred(x, list[idx])) { - return true; - } - idx += 1; - } - return false; -} - -function _functionName(f) { - // String(x => x) evaluates to "x => x", so the pattern may not match. - var match = String(f).match(/^function (\w*)/); - return match == null ? '' : match[1]; -} - -/** - * Returns true if its arguments are identical, false otherwise. Values are - * identical if they reference the same memory. `NaN` is identical to `NaN`; - * `0` and `-0` are not identical. - * - * @func - * @memberOf R - * @since v0.15.0 - * @category Relation - * @sig a -> a -> Boolean - * @param {*} a - * @param {*} b - * @return {Boolean} - * @example - * - * var o = {}; - * R.identical(o, o); //=> true - * R.identical(1, 1); //=> true - * R.identical(1, '1'); //=> false - * R.identical([], []); //=> false - * R.identical(0, -0); //=> false - * R.identical(NaN, NaN); //=> true - */ -var identical = /*#__PURE__*/_curry2(function identical(a, b) { - // SameValue algorithm - if (a === b) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - return a !== 0 || 1 / a === 1 / b; - } else { - // Step 6.a: NaN == NaN - return a !== a && b !== b; - } -}); - -/** - * private _uniqContentEquals function. - * That function is checking equality of 2 iterator contents with 2 assumptions - * - iterators lengths are the same - * - iterators values are unique - * - * false-positive result will be returned for comparision of, e.g. - * - [1,2,3] and [1,2,3,4] - * - [1,1,1] and [1,2,3] - * */ - -function _uniqContentEquals(aIterator, bIterator, stackA, stackB) { - var a = _arrayFromIterator(aIterator); - var b = _arrayFromIterator(bIterator); - - function eq(_a, _b) { - return _equals(_a, _b, stackA.slice(), stackB.slice()); - } - - // if *a* array contains any element that is not included in *b* - return !_containsWith(function (b, aItem) { - return !_containsWith(eq, aItem, b); - }, b, a); -} - -function _equals(a, b, stackA, stackB) { - if (identical(a, b)) { - return true; - } - - var typeA = type(a); - - if (typeA !== type(b)) { - return false; - } - - if (a == null || b == null) { - return false; - } - - if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') { - return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a); - } - - if (typeof a.equals === 'function' || typeof b.equals === 'function') { - return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a); - } - - switch (typeA) { - case 'Arguments': - case 'Array': - case 'Object': - if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') { - return a === b; - } - break; - case 'Boolean': - case 'Number': - case 'String': - if (!(typeof a === typeof b && identical(a.valueOf(), b.valueOf()))) { - return false; - } - break; - case 'Date': - if (!identical(a.valueOf(), b.valueOf())) { - return false; - } - break; - case 'Error': - return a.name === b.name && a.message === b.message; - case 'RegExp': - if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) { - return false; - } - break; - } - - var idx = stackA.length - 1; - while (idx >= 0) { - if (stackA[idx] === a) { - return stackB[idx] === b; - } - idx -= 1; - } - - switch (typeA) { - case 'Map': - if (a.size !== b.size) { - return false; - } - - return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b])); - case 'Set': - if (a.size !== b.size) { - return false; - } - - return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b])); - case 'Arguments': - case 'Array': - case 'Object': - case 'Boolean': - case 'Number': - case 'String': - case 'Date': - case 'Error': - case 'RegExp': - case 'Int8Array': - case 'Uint8Array': - case 'Uint8ClampedArray': - case 'Int16Array': - case 'Uint16Array': - case 'Int32Array': - case 'Uint32Array': - case 'Float32Array': - case 'Float64Array': - case 'ArrayBuffer': - break; - default: - // Values of other types are only equal if identical. - return false; - } - - var keysA = keys(a); - if (keysA.length !== keys(b).length) { - return false; - } - - var extendedStackA = stackA.concat([a]); - var extendedStackB = stackB.concat([b]); - - idx = keysA.length - 1; - while (idx >= 0) { - var key = keysA[idx]; - if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) { - return false; - } - idx -= 1; - } - return true; -} - -/** - * Returns `true` if its arguments are equivalent, `false` otherwise. Handles - * cyclical data structures. - * - * Dispatches symmetrically to the `equals` methods of both arguments, if - * present. - * - * @func - * @memberOf R - * @since v0.15.0 - * @category Relation - * @sig a -> b -> Boolean - * @param {*} a - * @param {*} b - * @return {Boolean} - * @example - * - * R.equals(1, 1); //=> true - * R.equals(1, '1'); //=> false - * R.equals([1, 2, 3], [1, 2, 3]); //=> true - * - * var a = {}; a.v = a; - * var b = {}; b.v = b; - * R.equals(a, b); //=> true - */ -var equals = /*#__PURE__*/_curry2(function equals(a, b) { - return _equals(a, b, [], []); -}); - -function _indexOf(list, a, idx) { - var inf, item; - // Array.prototype.indexOf doesn't exist below IE9 - if (typeof list.indexOf === 'function') { - switch (typeof a) { - case 'number': - if (a === 0) { - // manually crawl the list to distinguish between +0 and -0 - inf = 1 / a; - while (idx < list.length) { - item = list[idx]; - if (item === 0 && 1 / item === inf) { - return idx; - } - idx += 1; - } - return -1; - } else if (a !== a) { - // NaN - while (idx < list.length) { - item = list[idx]; - if (typeof item === 'number' && item !== item) { - return idx; - } - idx += 1; - } - return -1; - } - // non-zero numbers can utilise Set - return list.indexOf(a, idx); - - // all these types can utilise Set - case 'string': - case 'boolean': - case 'function': - case 'undefined': - return list.indexOf(a, idx); - - case 'object': - if (a === null) { - // null can utilise Set - return list.indexOf(a, idx); - } - } - } - // anything else not covered above, defer to R.equals - while (idx < list.length) { - if (equals(list[idx], a)) { - return idx; - } - idx += 1; - } - return -1; -} - -function _contains(a, list) { - return _indexOf(list, a, 0) >= 0; -} - -function _quote(s) { - var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace - .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0'); - - return '"' + escaped.replace(/"/g, '\\"') + '"'; -} - -/** - * Polyfill from . - */ -var pad = function pad(n) { - return (n < 10 ? '0' : '') + n; -}; - -var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) { - return d.toISOString(); -} : function _toISOString(d) { - return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'; -}; - -function _complement(f) { - return function () { - return !f.apply(this, arguments); - }; -} - -function _filter(fn, list) { - var idx = 0; - var len = list.length; - var result = []; - - while (idx < len) { - if (fn(list[idx])) { - result[result.length] = list[idx]; - } - idx += 1; - } - return result; -} - -function _isObject(x) { - return Object.prototype.toString.call(x) === '[object Object]'; -} - -var XFilter = /*#__PURE__*/function () { - function XFilter(f, xf) { - this.xf = xf; - this.f = f; - } - XFilter.prototype['@@transducer/init'] = _xfBase.init; - XFilter.prototype['@@transducer/result'] = _xfBase.result; - XFilter.prototype['@@transducer/step'] = function (result, input) { - return this.f(input) ? this.xf['@@transducer/step'](result, input) : result; - }; - - return XFilter; -}(); - -var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) { - return new XFilter(f, xf); -}); - -/** - * Takes a predicate and a `Filterable`, and returns a new filterable of the - * same type containing the members of the given filterable which satisfy the - * given predicate. Filterable objects include plain objects or any object - * that has a filter method such as `Array`. - * - * Dispatches to the `filter` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> f a - * @param {Function} pred - * @param {Array} filterable - * @return {Array} Filterable - * @see R.reject, R.transduce, R.addIndex - * @example - * - * var isEven = n => n % 2 === 0; - * - * R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4] - * - * R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} - */ -var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) { - return _isObject(filterable) ? _reduce(function (acc, key) { - if (pred(filterable[key])) { - acc[key] = filterable[key]; - } - return acc; - }, {}, keys(filterable)) : - // else - _filter(pred, filterable); -})); - -/** - * The complement of [`filter`](#filter). - * - * Acts as a transducer if a transformer is given in list position. Filterable - * objects include plain objects or any object that has a filter method such - * as `Array`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> f a - * @param {Function} pred - * @param {Array} filterable - * @return {Array} - * @see R.filter, R.transduce, R.addIndex - * @example - * - * var isOdd = (n) => n % 2 === 1; - * - * R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4] - * - * R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4} - */ -var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) { - return filter(_complement(pred), filterable); -}); - -function _toString(x, seen) { - var recur = function recur(y) { - var xs = seen.concat([x]); - return _contains(y, xs) ? '' : _toString(y, xs); - }; - - // mapPairs :: (Object, [String]) -> [String] - var mapPairs = function (obj, keys$$1) { - return _map(function (k) { - return _quote(k) + ': ' + recur(obj[k]); - }, keys$$1.slice().sort()); - }; - - switch (Object.prototype.toString.call(x)) { - case '[object Arguments]': - return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))'; - case '[object Array]': - return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) { - return (/^\d+$/.test(k) - ); - }, keys(x)))).join(', ') + ']'; - case '[object Boolean]': - return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString(); - case '[object Date]': - return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')'; - case '[object Null]': - return 'null'; - case '[object Number]': - return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10); - case '[object String]': - return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x); - case '[object Undefined]': - return 'undefined'; - default: - if (typeof x.toString === 'function') { - var repr = x.toString(); - if (repr !== '[object Object]') { - return repr; - } - } - return '{' + mapPairs(x, keys(x)).join(', ') + '}'; - } -} - -/** - * Returns the string representation of the given value. `eval`'ing the output - * should result in a value equivalent to the input value. Many of the built-in - * `toString` methods do not satisfy this requirement. - * - * If the given value is an `[object Object]` with a `toString` method other - * than `Object.prototype.toString`, this method is invoked with no arguments - * to produce the return value. This means user-defined constructor functions - * can provide a suitable `toString` method. For example: - * - * function Point(x, y) { - * this.x = x; - * this.y = y; - * } - * - * Point.prototype.toString = function() { - * return 'new Point(' + this.x + ', ' + this.y + ')'; - * }; - * - * R.toString(new Point(1, 2)); //=> 'new Point(1, 2)' - * - * @func - * @memberOf R - * @since v0.14.0 - * @category String - * @sig * -> String - * @param {*} val - * @return {String} - * @example - * - * R.toString(42); //=> '42' - * R.toString('abc'); //=> '"abc"' - * R.toString([1, 2, 3]); //=> '[1, 2, 3]' - * R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}' - * R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")' - */ -var toString$1 = /*#__PURE__*/_curry1(function toString(val) { - return _toString(val, []); -}); - -/** - * Returns the result of concatenating the given lists or strings. - * - * Note: `R.concat` expects both arguments to be of the same type, - * unlike the native `Array.prototype.concat` method. It will throw - * an error if you `concat` an Array with a non-Array value. - * - * Dispatches to the `concat` method of the first argument, if present. - * Can also concatenate two members of a [fantasy-land - * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup). - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] -> [a] - * @sig String -> String -> String - * @param {Array|String} firstList The first list - * @param {Array|String} secondList The second list - * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of - * `secondList`. - * - * @example - * - * R.concat('ABC', 'DEF'); // 'ABCDEF' - * R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3] - * R.concat([], []); //=> [] - */ -var concat = /*#__PURE__*/_curry2(function concat(a, b) { - if (_isArray(a)) { - if (_isArray(b)) { - return a.concat(b); - } - throw new TypeError(toString$1(b) + ' is not an array'); - } - if (_isString(a)) { - if (_isString(b)) { - return a + b; - } - throw new TypeError(toString$1(b) + ' is not a string'); - } - if (a != null && _isFunction(a['fantasy-land/concat'])) { - return a['fantasy-land/concat'](b); - } - if (a != null && _isFunction(a.concat)) { - return a.concat(b); - } - throw new TypeError(toString$1(a) + ' does not have a method named "concat" or "fantasy-land/concat"'); -}); - -/** - * Returns `true` if the specified value is equal, in [`R.equals`](#equals) - * terms, to at least one element of the given list; `false` otherwise. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig a -> [a] -> Boolean - * @param {Object} a The item to compare against. - * @param {Array} list The array to consider. - * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise. - * @see R.any - * @example - * - * R.contains(3, [1, 2, 3]); //=> true - * R.contains(4, [1, 2, 3]); //=> false - * R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true - * R.contains([42], [[42]]); //=> true - */ -var contains$1 = /*#__PURE__*/_curry2(_contains); - -/** - * Accepts a converging function and a list of branching functions and returns - * a new function. When invoked, this new function is applied to some - * arguments, each branching function is applied to those same arguments. The - * results of each branching function are passed as arguments to the converging - * function to produce the return value. - * - * @func - * @memberOf R - * @since v0.4.2 - * @category Function - * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z) - * @param {Function} after A function. `after` will be invoked with the return values of - * `fn1` and `fn2` as its arguments. - * @param {Array} functions A list of functions. - * @return {Function} A new function. - * @see R.useWith - * @example - * - * var average = R.converge(R.divide, [R.sum, R.length]) - * average([1, 2, 3, 4, 5, 6, 7]) //=> 4 - * - * var strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower]) - * strangeConcat("Yodel") //=> "YODELyodel" - * - * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b)) - */ -var converge = /*#__PURE__*/_curry2(function converge(after, fns) { - return curryN(reduce(max, 0, pluck('length', fns)), function () { - var args = arguments; - var context = this; - return after.apply(context, _map(function (fn) { - return fn.apply(context, args); - }, fns)); - }); -}); - -var XReduceBy = /*#__PURE__*/function () { - function XReduceBy(valueFn, valueAcc, keyFn, xf) { - this.valueFn = valueFn; - this.valueAcc = valueAcc; - this.keyFn = keyFn; - this.xf = xf; - this.inputs = {}; - } - XReduceBy.prototype['@@transducer/init'] = _xfBase.init; - XReduceBy.prototype['@@transducer/result'] = function (result) { - var key; - for (key in this.inputs) { - if (_has(key, this.inputs)) { - result = this.xf['@@transducer/step'](result, this.inputs[key]); - if (result['@@transducer/reduced']) { - result = result['@@transducer/value']; - break; - } - } - } - this.inputs = null; - return this.xf['@@transducer/result'](result); - }; - XReduceBy.prototype['@@transducer/step'] = function (result, input) { - var key = this.keyFn(input); - this.inputs[key] = this.inputs[key] || [key, this.valueAcc]; - this.inputs[key][1] = this.valueFn(this.inputs[key][1], input); - return result; - }; - - return XReduceBy; -}(); - -var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) { - return new XReduceBy(valueFn, valueAcc, keyFn, xf); -}); - -/** - * Groups the elements of the list according to the result of calling - * the String-returning function `keyFn` on each element and reduces the elements - * of each group to a single value via the reducer function `valueFn`. - * - * This function is basically a more general [`groupBy`](#groupBy) function. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.20.0 - * @category List - * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a} - * @param {Function} valueFn The function that reduces the elements of each group to a single - * value. Receives two values, accumulator for a particular group and the current element. - * @param {*} acc The (initial) accumulator value for each group. - * @param {Function} keyFn The function that maps the list's element into a key. - * @param {Array} list The array to group. - * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of - * `valueFn` for elements which produced that key when passed to `keyFn`. - * @see R.groupBy, R.reduce - * @example - * - * var reduceToNamesBy = R.reduceBy((acc, student) => acc.concat(student.name), []); - * var namesByGrade = reduceToNamesBy(function(student) { - * var score = student.score; - * return score < 65 ? 'F' : - * score < 70 ? 'D' : - * score < 80 ? 'C' : - * score < 90 ? 'B' : 'A'; - * }); - * var students = [{name: 'Lucy', score: 92}, - * {name: 'Drew', score: 85}, - * // ... - * {name: 'Bart', score: 62}]; - * namesByGrade(students); - * // { - * // 'A': ['Lucy'], - * // 'B': ['Drew'] - * // // ..., - * // 'F': ['Bart'] - * // } - */ -var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) { - return _reduce(function (acc, elt) { - var key = keyFn(elt); - acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt); - return acc; - }, {}, list); -})); - -/** - * Counts the elements of a list according to how many match each value of a - * key generated by the supplied function. Returns an object mapping the keys - * produced by `fn` to the number of occurrences in the list. Note that all - * keys are coerced to strings because of how JavaScript objects work. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig (a -> String) -> [a] -> {*} - * @param {Function} fn The function used to map values to keys. - * @param {Array} list The list to count elements from. - * @return {Object} An object mapping keys to number of occurrences in the list. - * @example - * - * var numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2]; - * R.countBy(Math.floor)(numbers); //=> {'1': 3, '2': 2, '3': 1} - * - * var letters = ['a', 'b', 'A', 'a', 'B', 'c']; - * R.countBy(R.toLower)(letters); //=> {'a': 3, 'b': 2, 'c': 1} - */ -var countBy = /*#__PURE__*/reduceBy(function (acc, elem) { - return acc + 1; -}, 0); - -/** - * Decrements its argument. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Math - * @sig Number -> Number - * @param {Number} n - * @return {Number} n - 1 - * @see R.inc - * @example - * - * R.dec(42); //=> 41 - */ -var dec = /*#__PURE__*/add(-1); - -/** - * Finds the set (i.e. no duplicates) of all elements in the first list not - * contained in the second list. Objects and Arrays are compared in terms of - * value equality, not reference equality. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig [*] -> [*] -> [*] - * @param {Array} list1 The first list. - * @param {Array} list2 The second list. - * @return {Array} The elements in `list1` that are not in `list2`. - * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without - * @example - * - * R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2] - * R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5] - * R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}] - */ -var difference = /*#__PURE__*/_curry2(function difference(first, second) { - var out = []; - var idx = 0; - var firstLen = first.length; - while (idx < firstLen) { - if (!_contains(first[idx], second) && !_contains(first[idx], out)) { - out[out.length] = first[idx]; - } - idx += 1; - } - return out; -}); - -var XDropRepeatsWith = /*#__PURE__*/function () { - function XDropRepeatsWith(pred, xf) { - this.xf = xf; - this.pred = pred; - this.lastValue = undefined; - this.seenFirstValue = false; - } - - XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init; - XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result; - XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) { - var sameAsLast = false; - if (!this.seenFirstValue) { - this.seenFirstValue = true; - } else if (this.pred(this.lastValue, input)) { - sameAsLast = true; - } - this.lastValue = input; - return sameAsLast ? result : this.xf['@@transducer/step'](result, input); - }; - - return XDropRepeatsWith; -}(); - -var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) { - return new XDropRepeatsWith(pred, xf); -}); - -/** - * Returns the nth element of the given list or string. If n is negative the - * element at index length + n is returned. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig Number -> [a] -> a | Undefined - * @sig Number -> String -> String - * @param {Number} offset - * @param {*} list - * @return {*} - * @example - * - * var list = ['foo', 'bar', 'baz', 'quux']; - * R.nth(1, list); //=> 'bar' - * R.nth(-1, list); //=> 'quux' - * R.nth(-99, list); //=> undefined - * - * R.nth(2, 'abc'); //=> 'c' - * R.nth(3, 'abc'); //=> '' - * @symb R.nth(-1, [a, b, c]) = c - * @symb R.nth(0, [a, b, c]) = a - * @symb R.nth(1, [a, b, c]) = b - */ -var nth = /*#__PURE__*/_curry2(function nth(offset, list) { - var idx = offset < 0 ? list.length + offset : offset; - return _isString(list) ? list.charAt(idx) : list[idx]; -}); - -/** - * Returns the last element of the given list or string. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig [a] -> a | Undefined - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.init, R.head, R.tail - * @example - * - * R.last(['fi', 'fo', 'fum']); //=> 'fum' - * R.last([]); //=> undefined - * - * R.last('abc'); //=> 'c' - * R.last(''); //=> '' - */ -var last = /*#__PURE__*/nth(-1); - -/** - * Returns a new list without any consecutively repeating elements. Equality is - * determined by applying the supplied predicate to each pair of consecutive elements. The - * first element in a series of equal elements will be preserved. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.14.0 - * @category List - * @sig ((a, a) -> Boolean) -> [a] -> [a] - * @param {Function} pred A predicate used to test whether two items are equal. - * @param {Array} list The array to consider. - * @return {Array} `list` without repeating elements. - * @see R.transduce - * @example - * - * var l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3]; - * R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3] - */ -var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) { - var result = []; - var idx = 1; - var len = list.length; - if (len !== 0) { - result[0] = list[0]; - while (idx < len) { - if (!pred(last(result), list[idx])) { - result[result.length] = list[idx]; - } - idx += 1; - } - } - return result; -})); - -/** - * Returns a new list without any consecutively repeating elements. - * [`R.equals`](#equals) is used to determine equality. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.14.0 - * @category List - * @sig [a] -> [a] - * @param {Array} list The array to consider. - * @return {Array} `list` without repeating elements. - * @see R.transduce - * @example - * - * R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2] - */ -var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals))); - -/** - * Returns the empty value of its argument's type. Ramda defines the empty - * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other - * types are supported if they define `.empty`, - * `.prototype.empty` or implement the - * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid). - * - * Dispatches to the `empty` method of the first argument, if present. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category Function - * @sig a -> a - * @param {*} x - * @return {*} - * @example - * - * R.empty(Just(42)); //=> Nothing() - * R.empty([1, 2, 3]); //=> [] - * R.empty('unicorns'); //=> '' - * R.empty({x: 1, y: 2}); //=> {} - */ -var empty = /*#__PURE__*/_curry1(function empty(x) { - return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () { - return arguments; - }() : - // else - void 0; -}); - -/** - * Returns a new function much like the supplied one, except that the first two - * arguments' order is reversed. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z) - * @param {Function} fn The function to invoke with its first two parameters reversed. - * @return {*} The result of invoking `fn` with its first two parameters' order reversed. - * @example - * - * var mergeThree = (a, b, c) => [].concat(a, b, c); - * - * mergeThree(1, 2, 3); //=> [1, 2, 3] - * - * R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3] - * @symb R.flip(f)(a, b, c) = f(b, a, c) - */ -var flip = /*#__PURE__*/_curry1(function flip(fn) { - return curryN(fn.length, function (a, b) { - var args = Array.prototype.slice.call(arguments, 0); - args[0] = b; - args[1] = a; - return fn.apply(this, args); - }); -}); - -/** - * Iterate over an input `list`, calling a provided function `fn` for each - * element in the list. - * - * `fn` receives one argument: *(value)*. - * - * Note: `R.forEach` does not skip deleted or unassigned indices (sparse - * arrays), unlike the native `Array.prototype.forEach` method. For more - * details on this behavior, see: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description - * - * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns - * the original array. In some libraries this function is named `each`. - * - * Dispatches to the `forEach` method of the second argument, if present. - * - * @func - * @memberOf R - * @since v0.1.1 - * @category List - * @sig (a -> *) -> [a] -> [a] - * @param {Function} fn The function to invoke. Receives one argument, `value`. - * @param {Array} list The list to iterate over. - * @return {Array} The original list. - * @see R.addIndex - * @example - * - * var printXPlusFive = x => console.log(x + 5); - * R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3] - * // logs 6 - * // logs 7 - * // logs 8 - * @symb R.forEach(f, [a, b, c]) = [a, b, c] - */ -var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) { - var len = list.length; - var idx = 0; - while (idx < len) { - fn(list[idx]); - idx += 1; - } - return list; -})); - -/** - * Iterate over an input `object`, calling a provided function `fn` for each - * key and value in the object. - * - * `fn` receives three argument: *(value, key, obj)*. - * - * @func - * @memberOf R - * @since v0.23.0 - * @category Object - * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a - * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`. - * @param {Object} obj The object to iterate over. - * @return {Object} The original object. - * @example - * - * var printKeyConcatValue = (value, key) => console.log(key + ':' + value); - * R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2} - * // logs x:1 - * // logs y:2 - * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b} - */ -var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) { - var keyList = keys(obj); - var idx = 0; - while (idx < keyList.length) { - var key = keyList[idx]; - fn(obj[key], key, obj); - idx += 1; - } - return obj; -}); - -/** - * Creates a new object from a list key-value pairs. If a key appears in - * multiple pairs, the rightmost pair is included in the object. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig [[k,v]] -> {k: v} - * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object. - * @return {Object} The object made by pairing up `keys` and `values`. - * @see R.toPairs, R.pair - * @example - * - * R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3} - */ -var fromPairs = /*#__PURE__*/_curry1(function fromPairs(pairs) { - var result = {}; - var idx = 0; - while (idx < pairs.length) { - result[pairs[idx][0]] = pairs[idx][1]; - idx += 1; - } - return result; -}); - -/** - * Splits a list into sub-lists stored in an object, based on the result of - * calling a String-returning function on each element, and grouping the - * results according to values returned. - * - * Dispatches to the `groupBy` method of the second argument, if present. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig (a -> String) -> [a] -> {String: [a]} - * @param {Function} fn Function :: a -> String - * @param {Array} list The array to group - * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements - * that produced that key when passed to `fn`. - * @see R.transduce - * @example - * - * var byGrade = R.groupBy(function(student) { - * var score = student.score; - * return score < 65 ? 'F' : - * score < 70 ? 'D' : - * score < 80 ? 'C' : - * score < 90 ? 'B' : 'A'; - * }); - * var students = [{name: 'Abby', score: 84}, - * {name: 'Eddy', score: 58}, - * // ... - * {name: 'Jack', score: 69}]; - * byGrade(students); - * // { - * // 'A': [{name: 'Dianne', score: 99}], - * // 'B': [{name: 'Abby', score: 84}] - * // // ..., - * // 'F': [{name: 'Eddy', score: 58}] - * // } - */ -var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) { - if (acc == null) { - acc = []; - } - acc.push(item); - return acc; -}, null))); - -/** - * Returns the first element of the given list or string. In some libraries - * this function is named `first`. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> a | Undefined - * @sig String -> String - * @param {Array|String} list - * @return {*} - * @see R.tail, R.init, R.last - * @example - * - * R.head(['fi', 'fo', 'fum']); //=> 'fi' - * R.head([]); //=> undefined - * - * R.head('abc'); //=> 'a' - * R.head(''); //=> '' - */ -var head = /*#__PURE__*/nth(0); - -function _identity(x) { - return x; -} - -/** - * A function that does nothing but return the parameter supplied to it. Good - * as a default or placeholder function. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig a -> a - * @param {*} x The value to return. - * @return {*} The input value, `x`. - * @example - * - * R.identity(1); //=> 1 - * - * var obj = {}; - * R.identity(obj) === obj; //=> true - * @symb R.identity(a) = a - */ -var identity = /*#__PURE__*/_curry1(_identity); - -/** - * Increments its argument. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category Math - * @sig Number -> Number - * @param {Number} n - * @return {Number} n + 1 - * @see R.dec - * @example - * - * R.inc(42); //=> 43 - */ -var inc = /*#__PURE__*/add(1); - -/** - * Given a function that generates a key, turns a list of objects into an - * object indexing the objects by the given key. Note that if multiple - * objects generate the same value for the indexing key only the last value - * will be included in the generated object. - * - * Acts as a transducer if a transformer is given in list position. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category List - * @sig (a -> String) -> [{k: v}] -> {k: {k: v}} - * @param {Function} fn Function :: a -> String - * @param {Array} array The array of objects to index - * @return {Object} An object indexing each array element by the given property. - * @example - * - * var list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}]; - * R.indexBy(R.prop('id'), list); - * //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}} - */ -var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) { - return elem; -}, null); - -/** - * Returns all but the last element of the given list or string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category List - * @sig [a] -> [a] - * @sig String -> String - * @param {*} list - * @return {*} - * @see R.last, R.head, R.tail - * @example - * - * R.init([1, 2, 3]); //=> [1, 2] - * R.init([1, 2]); //=> [1] - * R.init([1]); //=> [] - * R.init([]); //=> [] - * - * R.init('abc'); //=> 'ab' - * R.init('ab'); //=> 'a' - * R.init('a'); //=> '' - * R.init(''); //=> '' - */ -var init = /*#__PURE__*/slice(0, -1); - -var _Set = /*#__PURE__*/function () { - function _Set() { - /* globals Set */ - this._nativeSet = typeof Set === 'function' ? new Set() : null; - this._items = {}; - } - - // until we figure out why jsdoc chokes on this - // @param item The item to add to the Set - // @returns {boolean} true if the item did not exist prior, otherwise false - // - _Set.prototype.add = function (item) { - return !hasOrAdd(item, true, this); - }; - - // - // @param item The item to check for existence in the Set - // @returns {boolean} true if the item exists in the Set, otherwise false - // - _Set.prototype.has = function (item) { - return hasOrAdd(item, false, this); - }; - - // - // Combines the logic for checking whether an item is a member of the set and - // for adding a new item to the set. - // - // @param item The item to check or add to the Set instance. - // @param shouldAdd If true, the item will be added to the set if it doesn't - // already exist. - // @param set The set instance to check or add to. - // @return {boolean} true if the item already existed, otherwise false. - // - return _Set; -}(); - -function hasOrAdd(item, shouldAdd, set) { - var type = typeof item; - var prevSize, newSize; - switch (type) { - case 'string': - case 'number': - // distinguish between +0 and -0 - if (item === 0 && 1 / item === -Infinity) { - if (set._items['-0']) { - return true; - } else { - if (shouldAdd) { - set._items['-0'] = true; - } - return false; - } - } - // these types can all utilise the native Set - if (set._nativeSet !== null) { - if (shouldAdd) { - prevSize = set._nativeSet.size; - set._nativeSet.add(item); - newSize = set._nativeSet.size; - return newSize === prevSize; - } else { - return set._nativeSet.has(item); - } - } else { - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = {}; - set._items[type][item] = true; - } - return false; - } else if (item in set._items[type]) { - return true; - } else { - if (shouldAdd) { - set._items[type][item] = true; - } - return false; - } - } - - case 'boolean': - // set._items['boolean'] holds a two element array - // representing [ falseExists, trueExists ] - if (type in set._items) { - var bIdx = item ? 1 : 0; - if (set._items[type][bIdx]) { - return true; - } else { - if (shouldAdd) { - set._items[type][bIdx] = true; - } - return false; - } - } else { - if (shouldAdd) { - set._items[type] = item ? [false, true] : [true, false]; - } - return false; - } - - case 'function': - // compare functions for reference equality - if (set._nativeSet !== null) { - if (shouldAdd) { - prevSize = set._nativeSet.size; - set._nativeSet.add(item); - newSize = set._nativeSet.size; - return newSize === prevSize; - } else { - return set._nativeSet.has(item); - } - } else { - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = [item]; - } - return false; - } - if (!_contains(item, set._items[type])) { - if (shouldAdd) { - set._items[type].push(item); - } - return false; - } - return true; - } - - case 'undefined': - if (set._items[type]) { - return true; - } else { - if (shouldAdd) { - set._items[type] = true; - } - return false; - } - - case 'object': - if (item === null) { - if (!set._items['null']) { - if (shouldAdd) { - set._items['null'] = true; - } - return false; - } - return true; - } - /* falls through */ - default: - // reduce the search size of heterogeneous sets by creating buckets - // for each type. - type = Object.prototype.toString.call(item); - if (!(type in set._items)) { - if (shouldAdd) { - set._items[type] = [item]; - } - return false; - } - // scan through all previously applied items - if (!_contains(item, set._items[type])) { - if (shouldAdd) { - set._items[type].push(item); - } - return false; - } - return true; - } -} - -/** - * Returns a new list containing only one copy of each element in the original - * list, based upon the value returned by applying the supplied function to - * each list element. Prefers the first item if the supplied function produces - * the same value on two items. [`R.equals`](#equals) is used for comparison. - * - * @func - * @memberOf R - * @since v0.16.0 - * @category List - * @sig (a -> b) -> [a] -> [a] - * @param {Function} fn A function used to produce a value to use during comparisons. - * @param {Array} list The array to consider. - * @return {Array} The list of unique items. - * @example - * - * R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10] - */ -var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) { - var set = new _Set(); - var result = []; - var idx = 0; - var appliedItem, item; - - while (idx < list.length) { - item = list[idx]; - appliedItem = fn(item); - if (set.add(appliedItem)) { - result.push(item); - } - idx += 1; - } - return result; -}); - -/** - * Returns a new list containing only one copy of each element in the original - * list. [`R.equals`](#equals) is used to determine equality. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig [a] -> [a] - * @param {Array} list The array to consider. - * @return {Array} The list of unique items. - * @example - * - * R.uniq([1, 1, 2, 1]); //=> [1, 2] - * R.uniq([1, '1']); //=> [1, '1'] - * R.uniq([[42], [42]]); //=> [[42]] - */ -var uniq = /*#__PURE__*/uniqBy(identity); - -/** - * Turns a named method with a specified arity into a function that can be - * called directly supplied with arguments and a target object. - * - * The returned function is curried and accepts `arity + 1` parameters where - * the final parameter is the target object. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *) - * @param {Number} arity Number of arguments the returned function should take - * before the target object. - * @param {String} method Name of the method to call. - * @return {Function} A new curried function. - * @see R.construct - * @example - * - * var sliceFrom = R.invoker(1, 'slice'); - * sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm' - * var sliceFrom6 = R.invoker(2, 'slice')(6); - * sliceFrom6(8, 'abcdefghijklm'); //=> 'gh' - * @symb R.invoker(0, 'method')(o) = o['method']() - * @symb R.invoker(1, 'method')(a, o) = o['method'](a) - * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b) - */ -var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) { - return curryN(arity + 1, function () { - var target = arguments[arity]; - if (target != null && _isFunction(target[method])) { - return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity)); - } - throw new TypeError(toString$1(target) + ' does not have a method named "' + method + '"'); - }); -}); - -/** - * Returns `true` if the given value is its type's empty value; `false` - * otherwise. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Logic - * @sig a -> Boolean - * @param {*} x - * @return {Boolean} - * @see R.empty - * @example - * - * R.isEmpty([1, 2, 3]); //=> false - * R.isEmpty([]); //=> true - * R.isEmpty(''); //=> true - * R.isEmpty(null); //=> false - * R.isEmpty({}); //=> true - * R.isEmpty({length: 0}); //=> false - */ -var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) { - return x != null && equals(x, empty(x)); -}); - -/** - * Returns a string made by inserting the `separator` between each element and - * concatenating all the elements into a single string. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig String -> [a] -> String - * @param {Number|String} separator The string used to separate the elements. - * @param {Array} xs The elements to join into a string. - * @return {String} str The string made by concatenating `xs` with `separator`. - * @see R.split - * @example - * - * var spacer = R.join(' '); - * spacer(['a', 2, 3.4]); //=> 'a 2 3.4' - * R.join('|', [1, 2, 3]); //=> '1|2|3' - */ -var join = /*#__PURE__*/invoker(1, 'join'); - -/** - * juxt applies a list of functions to a list of values. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Function - * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n]) - * @param {Array} fns An array of functions - * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters. - * @see R.applySpec - * @example - * - * var getRange = R.juxt([Math.min, Math.max]); - * getRange(3, 4, 9, -3); //=> [-3, 9] - * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)] - */ -var juxt = /*#__PURE__*/_curry1(function juxt(fns) { - return converge(function () { - return Array.prototype.slice.call(arguments, 0); - }, fns); -}); - -function _isNumber(x) { - return Object.prototype.toString.call(x) === '[object Number]'; -} - -/** - * Returns the number of elements in the array by returning `list.length`. - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig [a] -> Number - * @param {Array} list The array to inspect. - * @return {Number} The length of the array. - * @example - * - * R.length([]); //=> 0 - * R.length([1, 2, 3]); //=> 3 - */ -var length = /*#__PURE__*/_curry1(function length(list) { - return list != null && _isNumber(list.length) ? list.length : NaN; -}); - -/** - * Adds together all the elements of a list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig [Number] -> Number - * @param {Array} list An array of numbers - * @return {Number} The sum of all the numbers in the list. - * @see R.reduce - * @example - * - * R.sum([2,4,6,8,100,1]); //=> 121 - */ -var sum = /*#__PURE__*/reduce(add, 0); - -/** - * A customisable version of [`R.memoize`](#memoize). `memoizeWith` takes an - * additional function that will be applied to a given argument set and used to - * create the cache key under which the results of the function to be memoized - * will be stored. Care must be taken when implementing key generation to avoid - * clashes that may overwrite previous entries erroneously. - * - * - * @func - * @memberOf R - * @since v0.24.0 - * @category Function - * @sig (*... -> String) -> (*... -> a) -> (*... -> a) - * @param {Function} fn The function to generate the cache key. - * @param {Function} fn The function to memoize. - * @return {Function} Memoized version of `fn`. - * @see R.memoize - * @example - * - * let count = 0; - * const factorial = R.memoizeWith(R.identity, n => { - * count += 1; - * return R.product(R.range(1, n + 1)); - * }); - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * count; //=> 1 - */ -var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) { - var cache = {}; - return _arity(fn.length, function () { - var key = mFn.apply(this, arguments); - if (!_has(key, cache)) { - cache[key] = fn.apply(this, arguments); - } - return cache[key]; - }); -}); - -/** - * Creates a new function that, when invoked, caches the result of calling `fn` - * for a given argument set and returns the result. Subsequent calls to the - * memoized `fn` with the same argument set will not result in an additional - * call to `fn`; instead, the cached result for that set of arguments will be - * returned. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig (*... -> a) -> (*... -> a) - * @param {Function} fn The function to memoize. - * @return {Function} Memoized version of `fn`. - * @see R.memoizeWith - * @deprecated since v0.25.0 - * @example - * - * let count = 0; - * const factorial = R.memoize(n => { - * count += 1; - * return R.product(R.range(1, n + 1)); - * }); - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * factorial(5); //=> 120 - * count; //=> 1 - */ -var memoize = /*#__PURE__*/memoizeWith(function () { - return toString$1(arguments); -}); - -/** - * Creates a new object with the own properties of the two provided objects. If - * a key exists in both objects, the provided function is applied to the key - * and the values associated with the key in each object, with the result being - * used as the value associated with the key in the returned object. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Object - * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a} - * @param {Function} fn - * @param {Object} l - * @param {Object} r - * @return {Object} - * @see R.mergeDeepWithKey, R.merge, R.mergeWith - * @example - * - * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r - * R.mergeWithKey(concatValues, - * { a: true, thing: 'foo', values: [10, 20] }, - * { b: true, thing: 'bar', values: [15, 35] }); - * //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] } - * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 } - */ -var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) { - var result = {}; - var k; - - for (k in l) { - if (_has(k, l)) { - result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k]; - } - } - - for (k in r) { - if (_has(k, r) && !_has(k, result)) { - result[k] = r[k]; - } - } - - return result; -}); - -/** - * Creates a new object with the own properties of the two provided objects. If - * a key exists in both objects, the provided function is applied to the values - * associated with the key in each object, with the result being used as the - * value associated with the key in the returned object. - * - * @func - * @memberOf R - * @since v0.19.0 - * @category Object - * @sig ((a, a) -> a) -> {a} -> {a} -> {a} - * @param {Function} fn - * @param {Object} l - * @param {Object} r - * @return {Object} - * @see R.mergeDeepWith, R.merge, R.mergeWithKey - * @example - * - * R.mergeWith(R.concat, - * { a: true, values: [10, 20] }, - * { b: true, values: [15, 35] }); - * //=> { a: true, b: true, values: [10, 20, 15, 35] } - */ -var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) { - return mergeWithKey(function (_, _l, _r) { - return fn(_l, _r); - }, l, r); -}); - -/** - * Multiplies two numbers. Equivalent to `a * b` but curried. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig Number -> Number -> Number - * @param {Number} a The first value. - * @param {Number} b The second value. - * @return {Number} The result of `a * b`. - * @see R.divide - * @example - * - * var double = R.multiply(2); - * var triple = R.multiply(3); - * double(3); //=> 6 - * triple(4); //=> 12 - * R.multiply(2, 5); //=> 10 - */ -var multiply = /*#__PURE__*/_curry2(function multiply(a, b) { - return a * b; -}); - -function _createPartialApplicator(concat) { - return _curry2(function (fn, args) { - return _arity(Math.max(0, fn.length - args.length), function () { - return fn.apply(this, concat(args, arguments)); - }); - }); -} - -/** - * Takes a function `f` and a list of arguments, and returns a function `g`. - * When applied, `g` returns the result of applying `f` to the arguments - * provided to `g` followed by the arguments provided initially. - * - * @func - * @memberOf R - * @since v0.10.0 - * @category Function - * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x) - * @param {Function} f - * @param {Array} args - * @return {Function} - * @see R.partial - * @example - * - * var greet = (salutation, title, firstName, lastName) => - * salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!'; - * - * var greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']); - * - * greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!' - * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b) - */ -var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat)); - -/** - * Takes a predicate and a list or other `Filterable` object and returns the - * pair of filterable objects of the same type of elements which do and do not - * satisfy, the predicate, respectively. Filterable objects include plain objects or any object - * that has a filter method such as `Array`. - * - * @func - * @memberOf R - * @since v0.1.4 - * @category List - * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a] - * @param {Function} pred A predicate to determine which side the element belongs to. - * @param {Array} filterable the list (or other filterable) to partition. - * @return {Array} An array, containing first the subset of elements that satisfy the - * predicate, and second the subset of elements that do not satisfy. - * @see R.filter, R.reject - * @example - * - * R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); - * // => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] - * - * R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' }); - * // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ] - */ -var partition = /*#__PURE__*/juxt([filter, reject]); - -/** - * Similar to `pick` except that this one includes a `key: undefined` pair for - * properties that don't exist. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @sig [k] -> {k: v} -> {k: v} - * @param {Array} names an array of String property names to copy onto a new object - * @param {Object} obj The object to copy from - * @return {Object} A new object with only properties from `names` on it. - * @see R.pick - * @example - * - * R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4} - * R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined} - */ -var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) { - var result = {}; - var idx = 0; - var len = names.length; - while (idx < len) { - var name = names[idx]; - result[name] = obj[name]; - idx += 1; - } - return result; -}); - -/** - * Multiplies together all the elements of a list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Math - * @sig [Number] -> Number - * @param {Array} list An array of numbers - * @return {Number} The product of all the numbers in the list. - * @see R.reduce - * @example - * - * R.product([2,4,6,8,100,1]); //=> 38400 - */ -var product = /*#__PURE__*/reduce(multiply, 1); - -/** - * Accepts a function `fn` and a list of transformer functions and returns a - * new curried function. When the new function is invoked, it calls the - * function `fn` with parameters consisting of the result of calling each - * supplied handler on successive arguments to the new function. - * - * If more arguments are passed to the returned function than transformer - * functions, those arguments are passed directly to `fn` as additional - * parameters. If you expect additional arguments that don't need to be - * transformed, although you can ignore them, it's best to pass an identity - * function so that the new function reports the correct arity. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Function - * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z) - * @param {Function} fn The function to wrap. - * @param {Array} transformers A list of transformer functions - * @return {Function} The wrapped function. - * @see R.converge - * @example - * - * R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81 - * R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81 - * R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32 - * R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32 - * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b)) - */ -var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) { - return curryN(transformers.length, function () { - var args = []; - var idx = 0; - while (idx < transformers.length) { - args.push(transformers[idx].call(this, arguments[idx])); - idx += 1; - } - return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length))); - }); -}); - -/** - * Reasonable analog to SQL `select` statement. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Object - * @category Relation - * @sig [k] -> [{k: v}] -> [{k: v}] - * @param {Array} props The property names to project - * @param {Array} objs The objects to query - * @return {Array} An array of objects with just the `props` properties. - * @example - * - * var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}; - * var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}; - * var kids = [abby, fred]; - * R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}] - */ -var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity - -/** - * Returns a copy of the list, sorted according to the comparator function, - * which should accept two values at a time and return a negative number if the - * first value is smaller, a positive number if it's larger, and zero if they - * are equal. Please note that this is a **copy** of the list. It does not - * modify the original. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category List - * @sig ((a, a) -> Number) -> [a] -> [a] - * @param {Function} comparator A sorting function :: a -> b -> Int - * @param {Array} list The list to sort - * @return {Array} a new array with its elements sorted by the comparator function. - * @example - * - * var diff = function(a, b) { return a - b; }; - * R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7] - */ -var sort = /*#__PURE__*/_curry2(function sort(comparator, list) { - return Array.prototype.slice.call(list, 0).sort(comparator); -}); - -/** - * Splits a string into an array of strings based on the given - * separator. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category String - * @sig (String | RegExp) -> String -> [String] - * @param {String|RegExp} sep The pattern. - * @param {String} str The string to separate into an array. - * @return {Array} The array of strings from `str` separated by `str`. - * @see R.join - * @example - * - * var pathComponents = R.split('/'); - * R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node'] - * - * R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd'] - */ -var split = /*#__PURE__*/invoker(1, 'split'); - -/** - * The lower case version of a string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category String - * @sig String -> String - * @param {String} str The string to lower case. - * @return {String} The lower case version of `str`. - * @see R.toUpper - * @example - * - * R.toLower('XYZ'); //=> 'xyz' - */ -var toLower = /*#__PURE__*/invoker(0, 'toLowerCase'); - -/** - * Converts an object into an array of key, value arrays. Only the object's - * own properties are used. - * Note that the order of the output array is not guaranteed to be consistent - * across different JS platforms. - * - * @func - * @memberOf R - * @since v0.4.0 - * @category Object - * @sig {String: *} -> [[String,*]] - * @param {Object} obj The object to extract from - * @return {Array} An array of key, value arrays from the object's own properties. - * @see R.fromPairs - * @example - * - * R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]] - */ -var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) { - var pairs = []; - for (var prop in obj) { - if (_has(prop, obj)) { - pairs[pairs.length] = [prop, obj[prop]]; - } - } - return pairs; -}); - -/** - * The upper case version of a string. - * - * @func - * @memberOf R - * @since v0.9.0 - * @category String - * @sig String -> String - * @param {String} str The string to upper case. - * @return {String} The upper case version of `str`. - * @see R.toLower - * @example - * - * R.toUpper('abc'); //=> 'ABC' - */ -var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase'); - -/** - * Initializes a transducer using supplied iterator function. Returns a single - * item by iterating through the list, successively calling the transformed - * iterator function and passing it an accumulator value and the current value - * from the array, and then passing the result to the next call. - * - * The iterator function receives two values: *(acc, value)*. It will be - * wrapped as a transformer to initialize the transducer. A transformer can be - * passed directly in place of an iterator function. In both cases, iteration - * may be stopped early with the [`R.reduced`](#reduced) function. - * - * A transducer is a function that accepts a transformer and returns a - * transformer and can be composed directly. - * - * A transformer is an an object that provides a 2-arity reducing iterator - * function, step, 0-arity initial value function, init, and 1-arity result - * extraction function, result. The step function is used as the iterator - * function in reduce. The result function is used to convert the final - * accumulator into the return type and in most cases is - * [`R.identity`](#identity). The init function can be used to provide an - * initial accumulator, but is ignored by transduce. - * - * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer. - * - * @func - * @memberOf R - * @since v0.12.0 - * @category List - * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a - * @param {Function} xf The transducer function. Receives a transformer and returns a transformer. - * @param {Function} fn The iterator function. Receives two values, the accumulator and the - * current element from the array. Wrapped as transformer, if necessary, and used to - * initialize the transducer - * @param {*} acc The initial accumulator value. - * @param {Array} list The list to iterate over. - * @return {*} The final, accumulated value. - * @see R.reduce, R.reduced, R.into - * @example - * - * var numbers = [1, 2, 3, 4]; - * var transducer = R.compose(R.map(R.add(1)), R.take(2)); - * R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3] - * - * var isOdd = (x) => x % 2 === 1; - * var firstOddTransducer = R.compose(R.filter(isOdd), R.take(1)); - * R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1] - */ -var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) { - return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list); -}); - -var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF'; -var zeroWidth = '\u200b'; -var hasProtoTrim = typeof String.prototype.trim === 'function'; -/** - * Removes (strips) whitespace from both ends of the string. - * - * @func - * @memberOf R - * @since v0.6.0 - * @category String - * @sig String -> String - * @param {String} str The string to trim. - * @return {String} Trimmed version of `str`. - * @example - * - * R.trim(' xyz '); //=> 'xyz' - * R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z'] - */ -var _trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? function trim(str) { - var beginRx = new RegExp('^[' + ws + '][' + ws + ']*'); - var endRx = new RegExp('[' + ws + '][' + ws + ']*$'); - return str.replace(beginRx, '').replace(endRx, ''); -} : function trim(str) { - return str.trim(); -}; - -/** - * Combines two lists into a set (i.e. no duplicates) composed of the elements - * of each list. - * - * @func - * @memberOf R - * @since v0.1.0 - * @category Relation - * @sig [*] -> [*] -> [*] - * @param {Array} as The first list. - * @param {Array} bs The second list. - * @return {Array} The first and second lists concatenated, with - * duplicates removed. - * @example - * - * R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4] - */ -var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat)); - -/** - * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from - * any [Chain](https://github.com/fantasyland/fantasy-land#chain). - * - * @func - * @memberOf R - * @since v0.3.0 - * @category List - * @sig Chain c => c (c a) -> c a - * @param {*} list - * @return {*} - * @see R.flatten, R.chain - * @example - * - * R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]] - * R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6] - */ -var unnest = /*#__PURE__*/chain(_identity); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { - return typeof obj; -} : function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; -}; - - - - - - - - - - - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - - - - - -var defineProperty = function (obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; -}; - -var _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; -}; - - - - - - - - - - - - - -var objectWithoutProperties = function (obj, keys) { - var target = {}; - - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; - } - - return target; -}; - - - - - - - -var slicedToArray = function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -}(); - -// urlEncode :: Object -> String -var urlEncode = pipe(filter(function (x) { - return x !== undefined; -}), toPairs, map(function (_ref) { - var _ref2 = slicedToArray(_ref, 2), - k = _ref2[0], - v = _ref2[1]; - - return k + '=' + encodeURIComponent(v); -}), join('&')); - -// appendQueryParam :: String -> String -> String -> String -var appendQueryParam = function appendQueryParam(key, value, url) { - var separator = contains$1('?', url) ? '&' : '?'; - return url + separator + urlEncode(defineProperty({}, key, value)); -}; - -var extractQueryParams = function extractQueryParams(url) { - return contains$1('?', url) ? queryStringToObj(split('?', url)[1]) : {}; -}; - -var queryStringToObj = pipe(split('&'), map(split('=')), fromPairs); - -var typeCheck = function typeCheck(name, expectedType, value) { - var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); - if (type !== expectedType) { - throw new TypeError('expected ' + name + ' to be of type ' + expectedType + ' but was of type ' + type); - } -}; - -// checks that all of an arrays elements are of the given type -var typeCheckArr = function typeCheckArr(name, expectedType, arr) { - if (!Array.isArray(arr)) { - throw new TypeError('expected ' + name + ' to be an array'); - } - arr.forEach(function (value, i) { - return typeCheck(name + '[' + i + ']', expectedType, value); - }); -}; - -// checks that all of an objects values are of the given type -var typeCheckObj = function typeCheckObj(name, expectedType, obj) { - typeCheck(name, 'object', obj); - forEachObjIndexed(function (value, key) { - return typeCheck(key, expectedType, value); - }, obj); -}; - -var checkOneOf = function checkOneOf(name, values, value) { - if (!contains$1(value, values)) { - throw new TypeError('expected ' + name + ' to be one of ' + values + ' but was ' + value); - } -}; - -var unixSeconds = function unixSeconds() { - return Math.floor(Date.now() / 1000); -}; - -// pointfree debugging - -var TokenProvider = -// TODO authContext -function TokenProvider() { - var _this = this; - - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - url = _ref.url; - - classCallCheck(this, TokenProvider); - - this.fetchToken = function () { - return !_this.cacheIsStale() ? Promise.resolve(_this.cachedToken) : _this.fetchFreshToken().then(function (_ref2) { - var token = _ref2.token, - expiresIn = _ref2.expiresIn; - - _this.cache(token, expiresIn); - return token; - }); - }; - - this.fetchFreshToken = function () { - return pusherPlatform_4({ - method: 'POST', - url: appendQueryParam('user_id', _this.userId, _this.url), - body: urlEncode({ grant_type: 'client_credentials' }), - headers: { - 'content-type': 'application/x-www-form-urlencoded' - } - }).then(function (res) { - var _JSON$parse = JSON.parse(res), - token = _JSON$parse.access_token, - expiresIn = _JSON$parse.expires_in; - - return { token: token, expiresIn: expiresIn }; - }); - }; - - this.cacheIsStale = function () { - return !_this.cachedToken || unixSeconds() > _this.cacheExpiresAt; - }; - - this.cache = function (token, expiresIn) { - _this.cachedToken = token; - _this.cacheExpiresAt = unixSeconds() + expiresIn; - }; - - this.clearCache = function () { - _this.cachedToken = undefined; - _this.cacheExpiresAt = undefined; - }; - - this.setUserId = function (userId) { - _this.clearCache(); - _this.userId = userId; - }; - - typeCheck('url', 'string', url); - this.url = url; -}; - -var parseBasicRoom = function parseBasicRoom(data) { - return { - createdAt: data.created_at, - createdByUserId: data.created_by_id, - deletedAt: data.deletedAt, - id: data.id, - isPrivate: data.private, - name: data.name, - updatedAt: data.updated_at, - userIds: data.member_user_ids - }; -}; - -var parseUser = function parseUser(data) { - return { - avatarURL: data.avatar_url, - createdAt: data.created_at, - customData: data.custom_data, - id: data.id, - name: data.name, - updatedAt: data.updated_at - }; -}; - -var parsePresence = function parsePresence(data) { - return { - lastSeenAt: data.last_seen_at, - state: contains$1(data.state, ['online', 'offline']) ? data.state : 'unknown', - userId: data.user_id - }; -}; - -var parseBasicMessage = function parseBasicMessage(data) { - return { - id: data.id, - senderId: data.user_id, - roomId: data.room_id, - text: data.text, - createdAt: data.created_at, - updatedAt: data.updated_at, - attachment: data.attachment && parseMessageAttachment(data.attachment) - }; -}; - -var parseFetchedAttachment = function parseFetchedAttachment(data) { - return { - file: { - name: data.file.name, - bytes: data.file.bytes, - lastModified: data.file.last_modified - }, - link: data.resource_link, - ttl: data.ttl - }; -}; - -var parseMessageAttachment = function parseMessageAttachment(data) { - return { - link: data.resource_link, - type: data.type, - fetchRequired: extractQueryParams(data.resource_link).chatkit_link === 'true' - }; -}; - -var Store = function Store() { - var _this = this; - - classCallCheck(this, Store); - this.pendingSets = []; - this.pendingGets = []; - - this.initialize = function (initialStore) { - _this.store = clone(initialStore); - forEach(function (_ref) { - var key = _ref.key, - value = _ref.value, - resolve = _ref.resolve; - - resolve(_this.store[key] = value); - }, _this.pendingSets); - forEach(function (_ref2) { - var key = _ref2.key, - resolve = _ref2.resolve; - - resolve(_this.store[key]); - }, _this.pendingGets); - }; - - this.set = function (key, value) { - if (_this.store) { - return Promise.resolve(_this.store[key] = value); - } else { - return new Promise(function (resolve) { - _this.pendingSets.push({ key: key, value: value, resolve: resolve }); - }); - } - }; - - this.get = function (key) { - if (_this.store) { - return Promise.resolve(_this.store[key]); - } else { - return new Promise(function (resolve) { - _this.pendingGets.push({ key: key, resolve: resolve }); - }); - } - }; - - this.pop = function (key) { - return _this.get(key).then(function (value) { - delete _this.store[key]; - return value; - }); - }; - - this.snapshot = function () { - return _this.store || {}; - }; - - this.getSync = function (key) { - return _this.store ? _this.store[key] : undefined; - }; -}; - -var UserStore = function UserStore(_ref) { - var _this = this; - - var instance = _ref.instance, - presenceStore = _ref.presenceStore, - logger = _ref.logger; - classCallCheck(this, UserStore); - this.store = new Store(); - this.initialize = this.store.initialize; - this.set = this.store.set; - - this.get = function (userId) { - return Promise.all([_this.store.get(userId).then(function (user) { - return user || _this.fetchBasicUser(userId); - }), _this.presenceStore.get(userId)]).then(function (_ref2) { - var _ref3 = slicedToArray(_ref2, 2), - user = _ref3[0], - presence = _ref3[1]; - - return _extends({}, user, { presence: presence }); - }); - }; - - this.fetchBasicUser = function (userId) { - return _this.instance.request({ - method: 'GET', - path: '/users/' + encodeURIComponent(userId) - }).then(function (res) { - var user = parseUser(JSON.parse(res)); - _this.set(userId, user); - return user; - }).catch(function (err) { - _this.logger.warn('error fetching user information:', err); - throw err; - }); - }; - - this.fetchMissingUsers = function (userIds) { - var missing = difference(userIds, map(prop('id'), values(_this.store.snapshot()))); - if (length(missing) === 0) { - return Promise.resolve(); - } - // TODO don't make simulatneous requests for the same users (question: what - // will actually cause this situation to arise? Receiving lots of messages - // in a room from a user who is no longer a member of said room?) - return _this.instance.request({ - method: 'GET', - path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') - }).then(pipe(JSON.parse, map(parseUser), forEach(function (user) { - return _this.set(user.id, user); - }))).catch(function (err) { - _this.logger.warn('error fetching missing users:', err); - throw err; - }); - }; - - this.snapshot = function () { - return map(_this.decorate, _this.store.snapshot()); - }; - - this.getSync = function (userId) { - return _this.decorate(_this.store.getSync(userId)); - }; - - this.decorate = function (user) { - return user ? _extends({}, user, { presence: _this.presenceStore.getSync(user.id) }) : undefined; - }; - - this.instance = instance; - this.presenceStore = presenceStore; - this.logger = logger; -}; - -var Room = function () { - function Room(basicRoom, userStore) { - classCallCheck(this, Room); - - this.createdAt = basicRoom.createdAt; - this.createdByUserId = basicRoom.createdByUserId; - this.deletedAt = basicRoom.deletedAt; - this.id = basicRoom.id; - this.isPrivate = basicRoom.isPrivate; - this.name = basicRoom.name; - this.updatedAt = basicRoom.updatedAt; - this.userIds = basicRoom.userIds; - this.userStore = userStore; - } - - createClass(Room, [{ - key: 'users', - get: function get$$1() { - var _this = this; - - return filter(function (user) { - return contains$1(user.id, _this.userIds); - }, values(this.userStore.snapshot())); - } - }]); - return Room; -}(); - -var RoomStore = function RoomStore(_ref) { - var _this = this; - - var instance = _ref.instance, - userStore = _ref.userStore, - logger = _ref.logger; - classCallCheck(this, RoomStore); - this.store = new Store(); - this.initialize = this.store.initialize; - this.set = curry(function (roomId, basicRoom) { - return _this.store.set(roomId, basicRoom).then(_this.decorate).then(function (room) { - return _this.userStore.fetchMissingUsers(room.userIds).then(function () { - return room; - }); - }); - }); - - this.get = function (roomId) { - return _this.store.get(roomId).then(function (basicRoom) { - return basicRoom || _this.fetchBasicRoom(roomId).then(_this.set(roomId)); - }).then(_this.decorate); - }; - - this.pop = function (roomId) { - return _this.store.pop(roomId).then(function (basicRoom) { - return basicRoom || _this.fetchBasicRoom(roomId); - }).then(_this.decorate); - }; - - this.addUserToRoom = function (roomId, userId) { - return _this.pop(roomId).then(function (r) { - return _this.set(roomId, _extends({}, r, { userIds: uniq(append(userId, r.userIds)) })); - }); - }; - - this.removeUserFromRoom = function (roomId, userId) { - return _this.pop(roomId).then(function (r) { - return _this.set(roomId, _extends({}, r, { userIds: filter(function (id) { - return id !== userId; - }, r.userIds) })); - }); - }; - - this.update = function (roomId, updates) { - return _this.store.pop(roomId).then(function (r) { - return _this.set(roomId, mergeWith(function (x, y) { - return y || x; - }, r, updates)); - }); - }; - - this.fetchBasicRoom = function (roomId) { - return _this.instance.request({ - method: 'GET', - path: '/rooms/' + roomId - }).then(pipe(JSON.parse, parseBasicRoom)).catch(function (err) { - _this.logger.warn('error fetching details for room ' + roomId + ':', err); - }); - }; - - this.snapshot = function () { - return map(_this.decorate, _this.store.snapshot()); - }; - - this.getSync = function (roomId) { - return _this.decorate(_this.store.getSync(roomId)); - }; - - this.decorate = function (basicRoom) { - return basicRoom ? new Room(basicRoom, _this.userStore) : undefined; - }; - - this.instance = instance; - this.userStore = userStore; - this.logger = logger; -}; - -var TYPING_INDICATOR_TTL = 1500; -var TYPING_INDICATOR_LEEWAY = 500; - -var TypingIndicators = function TypingIndicators(_ref) { - var _this = this; - - var userId = _ref.userId, - instance = _ref.instance, - logger = _ref.logger; - classCallCheck(this, TypingIndicators); - - this.sendThrottledRequest = function (roomId) { - var now = Date.now(); - var sent = _this.lastSentRequests[roomId]; - if (sent && now - sent < TYPING_INDICATOR_TTL - TYPING_INDICATOR_LEEWAY) { - return Promise.resolve(); - } - _this.lastSentRequests[roomId] = now; - return _this.instance.request({ - method: 'POST', - path: '/rooms/' + roomId + '/events', - json: { - name: 'typing_start', // soon to be 'is_typing' - user_id: _this.userId - } - }).catch(function (err) { - delete _this.typingRequestSent[roomId]; - _this.logger.warn('Error sending is_typing event in room ' + roomId, err); - throw err; - }); - }; - - this.onIsTyping = function (room, user, hooks, roomHooks) { - if (!_this.timers[room.id]) { - _this.timers[room.id] = {}; - } - if (_this.timers[room.id][user.id]) { - clearTimeout(_this.timers[room.id][user.id]); - } else { - _this.onStarted(room, user, hooks, roomHooks); - } - _this.timers[room.id][user.id] = setTimeout(function () { - _this.onStopped(room, user, hooks, roomHooks); - delete _this.timers[room.id][user.id]; - }, TYPING_INDICATOR_TTL); - }; - - this.onStarted = function (room, user, hooks, roomHooks) { - if (hooks.userStartedTyping) { - hooks.userStartedTyping(room, user); - } - if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { - roomHooks[room.id].userStartedTyping(user); - } - }; - - this.onStopped = function (room, user, hooks, roomHooks) { - if (hooks.userStoppedTyping) { - hooks.userStoppedTyping(room, user); - } - if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { - roomHooks[room.id].userStoppedTyping(user); - } - }; - - this.userId = userId; - this.instance = instance; - this.logger = logger; - this.lastSentRequests = {}; - this.timers = {}; -}; - -var UserSubscription = function () { - function UserSubscription(options) { - var _this = this; - - classCallCheck(this, UserSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'initial_state': - _this.onInitialState(body.data); - break; - case 'added_to_room': - _this.onAddedToRoom(body.data); - break; - case 'removed_from_room': - _this.onRemovedFromRoom(body.data); - break; - case 'user_joined': - _this.onUserJoined(body.data); - break; - case 'user_left': - _this.onUserLeft(body.data); - break; - case 'room_updated': - _this.onRoomUpdated(body.data); - break; - case 'room_deleted': - _this.onRoomDeleted(body.data); - break; - case 'typing_start': - // soon to be 'is_typing' - _this.onIsTyping(body.data); - break; - } - }; - - this.onInitialState = function (_ref2) { - var userData = _ref2.current_user, - roomsData = _ref2.rooms; - - _this.hooks.subscriptionEstablished({ - user: parseUser(userData), - basicRooms: map(parseBasicRoom, roomsData) - }); - }; - - this.onAddedToRoom = function (_ref3) { - var roomData = _ref3.room; - - var basicRoom = parseBasicRoom(roomData); - _this.roomStore.set(basicRoom.id, basicRoom).then(function (room) { - if (_this.hooks.addedToRoom) { - _this.hooks.addedToRoom(room); - } - }); - }; - - this.onRemovedFromRoom = function (_ref4) { - var roomId = _ref4.room_id; - - _this.roomStore.pop(roomId).then(function (room) { - // room will be undefined if we left with leaveRoom - if (room && _this.hooks.removedFromRoom) { - _this.hooks.removedFromRoom(room); - } - }); - }; - - this.onUserJoined = function (_ref5) { - var roomId = _ref5.room_id, - userId = _ref5.user_id; - - _this.roomStore.addUserToRoom(roomId, userId).then(function (room) { - _this.userStore.get(userId).then(function (user) { - if (_this.hooks.userJoinedRoom) { - _this.hooks.userJoinedRoom(room, user); - } - if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userJoined) { - _this.roomSubscriptions[roomId].hooks.userJoined(user); - } - }); - }); - }; - - this.onUserLeft = function (_ref6) { - var roomId = _ref6.room_id, - userId = _ref6.user_id; - - _this.roomStore.removeUserFromRoom(roomId, userId).then(function (room) { - _this.userStore.get(userId).then(function (user) { - if (_this.hooks.userLeftRoom) { - _this.hooks.userLeftRoom(room, user); - } - if (_this.roomSubscriptions[roomId] && _this.roomSubscriptions[roomId].hooks.userLeft) { - _this.roomSubscriptions[roomId].hooks.userLeft(user); - } - }); - }); - }; - - this.onRoomUpdated = function (_ref7) { - var roomData = _ref7.room; - - var updates = parseBasicRoom(roomData); - _this.roomStore.update(updates.id, updates).then(function (room) { - if (_this.hooks.roomUpdated) { - _this.hooks.roomUpdated(room); - } - }); - }; - - this.onRoomDeleted = function (_ref8) { - var roomId = _ref8.room_id; - - _this.roomStore.pop(roomId).then(function (room) { - if (room && _this.hooks.roomDeleted) { - _this.hooks.roomDeleted(room); - } - }); - }; - - this.onIsTyping = function (_ref9) { - var roomId = _ref9.room_id, - userId = _ref9.user_id; - - Promise.all([_this.roomStore.get(roomId), _this.userStore.get(userId)]).then(function (_ref10) { - var _ref11 = slicedToArray(_ref10, 2), - room = _ref11[0], - user = _ref11[1]; - - return _this.typingIndicators.onIsTyping(room, user, _this.hooks, map(prop('hooks'), _this.roomSubscriptions)); - }); - }; - - this.userId = options.userId; - this.hooks = options.hooks; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.typingIndicators = options.typingIndicators; - this.roomSubscriptions = options.roomSubscriptions; - } - - createClass(UserSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); - _this2.instance.subscribeNonResuming({ - path: '/users', - listeners: { - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return UserSubscription; -}(); - -var PresenceSubscription = function () { - function PresenceSubscription(options) { - var _this = this; - - classCallCheck(this, PresenceSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'initial_state': - _this.onInitialState(body.data); - break; - case 'presence_update': - _this.onPresenceUpdate(body.data); - break; - case 'join_room_presence_update': - _this.onJoinRoomPresenceUpdate(body.data); - break; - } - }; - - this.onInitialState = function (_ref2) { - var userStates = _ref2.user_states; - - _this.presenceStore.initialize(indexBy(prop('userId'), map(parsePresence, userStates))); - _this.hooks.subscriptionEstablished(); - }; - - this.onPresenceUpdate = function (data) { - var presence = parsePresence(data); - _this.presenceStore.set(presence.userId, presence).then(function (p) { - return _this.userStore.get(p.userId).then(function (user) { - switch (p.state) { - case 'online': - _this.onCameOnline(user); - break; - case 'offline': - _this.onWentOffline(user); - break; - } - }); - }); - }; - - this.onJoinRoomPresenceUpdate = function (_ref3) { - var userStates = _ref3.user_states; - return forEach(function (presence) { - return _this.presenceStore.set(presence.userId, presence); - }, map(parsePresence, userStates)); - }; - - this.onCameOnline = function (user) { - return _this.callRelevantHooks('userCameOnline', user); - }; - - this.onWentOffline = function (user) { - return _this.callRelevantHooks('userWentOffline', user); - }; - - this.callRelevantHooks = function (hookName, user) { - if (_this.hooks[hookName]) { - _this.hooks[hookName](user); - } - compose(forEach(function (sub) { - return _this.roomStore.get(sub.roomId).then(function (room) { - if (contains$1(user.id, room.userIds)) { - sub.hooks[hookName](user); - } - }); - }), filter(function (sub) { - return sub.hooks[hookName] !== undefined; - }), values)(_this.roomSubscriptions); - }; - - this.userId = options.userId; - this.hooks = options.hooks; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.presenceStore = options.presenceStore; - this.roomSubscriptions = options.roomSubscriptions; - } - - createClass(PresenceSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.hooks = _extends({}, _this2.hooks, { subscriptionEstablished: resolve }); - _this2.instance.subscribeNonResuming({ - path: '/users/' + encodeURIComponent(_this2.userId) + '/presence', - listeners: { - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return PresenceSubscription; -}(); - -var Message = function () { - function Message(basicMessage, userStore, roomStore) { - classCallCheck(this, Message); - - this.id = basicMessage.id; - this.senderId = basicMessage.senderId; - this.roomId = basicMessage.roomId; - this.text = basicMessage.text; - this.attachment = basicMessage.attachment; - this.createdAt = basicMessage.createdAt; - this.updatedAt = basicMessage.updatedAt; - this.userStore = userStore; - this.roomStore = roomStore; - } - - createClass(Message, [{ - key: "sender", - get: function get$$1() { - return this.userStore.getSync(this.senderId); - } - }, { - key: "room", - get: function get$$1() { - return this.roomStore.getSync(this.roomId); - } - }]); - return Message; -}(); - -var RoomSubscription = function () { - function RoomSubscription(options) { - var _this = this; - - classCallCheck(this, RoomSubscription); - - this.onEvent = function (_ref) { - var body = _ref.body; - - switch (body.event_name) { - case 'new_message': - _this.onNewMessage(body.data); - break; - } - }; - - this.onNewMessage = function (data) { - var pending = { - message: new Message(parseBasicMessage(data), _this.userStore, _this.roomStore), - ready: false - }; - _this.messageBuffer.push(pending); - _this.userStore.fetchMissingUsers([pending.message.senderId]).catch(function (err) { - _this.logger.error('error fetching missing user information:', err); - }).then(function () { - pending.ready = true; - _this.flushBuffer(); - }); - }; - - this.flushBuffer = function () { - while (!isEmpty(_this.messageBuffer) && head(_this.messageBuffer).ready) { - var message = _this.messageBuffer.shift().message; - if (_this.hooks.newMessage) { - _this.hooks.newMessage(message); - } - } - }; - - this.roomId = options.roomId; - this.hooks = options.hooks; - this.messageLimit = options.messageLimit; - this.userId = options.userId; - this.instance = options.instance; - this.userStore = options.userStore; - this.roomStore = options.roomStore; - this.messageBuffer = []; // { message, ready } - } - - createClass(RoomSubscription, [{ - key: 'connect', - value: function connect() { - var _this2 = this; - - return new Promise(function (resolve, reject) { - _this2.instance.subscribeNonResuming({ - path: '/rooms/' + _this2.roomId + '?' + urlEncode({ - message_limit: _this2.messageLimit - }), - listeners: { - onOpen: resolve, - onError: reject, - onEvent: _this2.onEvent - } - }); - }); - } - }]); - return RoomSubscription; -}(); - -var CurrentUser = function () { - function CurrentUser(_ref) { - var _this = this; - - var id = _ref.id, - apiInstance = _ref.apiInstance, - filesInstance = _ref.filesInstance; - classCallCheck(this, CurrentUser); - - this.isTypingIn = function (roomId) { - typeCheck('roomId', 'number', roomId); - return _this.typingIndicators.sendThrottledRequest(roomId); - }; - - this.createRoom = function () { - var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - var name = _ref2.name, - addUserIds = _ref2.addUserIds, - rest = objectWithoutProperties(_ref2, ['name', 'addUserIds']); - - name && typeCheck('name', 'string', name); - addUserIds && typeCheckArr('addUserIds', 'string', addUserIds); - return _this.apiInstance.request({ - method: 'POST', - path: '/rooms', - json: { - created_by_id: _this.id, - name: name, - private: !!rest.private, // private is a reserved word in strict mode! - user_ids: addUserIds - } - }).then(function (res) { - var basicRoom = parseBasicRoom(JSON.parse(res)); - return _this.roomStore.set(basicRoom.id, basicRoom); - }).catch(function (err) { - _this.logger.warn('error creating room:', err); - throw err; - }); - }; - - this.getJoinableRooms = function () { - return _this.apiInstance.request({ - method: 'GET', - path: '/users/' + _this.encodedId + '/rooms?joinable=true' - }).then(pipe(JSON.parse, map(parseBasicRoom))).catch(function (err) { - _this.logger.warn('error getting joinable rooms:', err); - throw err; - }); - }; - - this.getAllRooms = function () { - return _this.getJoinableRooms().then(concat(_this.rooms)); - }; - - this.joinRoom = function (roomId) { - typeCheck('roomId', 'number', roomId); - if (_this.isMemberOf(roomId)) { - return _this.roomStore.get(roomId); - } - return _this.apiInstance.request({ - method: 'POST', - path: '/users/' + _this.encodedId + '/rooms/' + roomId + '/join' - }).then(function (res) { - var basicRoom = parseBasicRoom(JSON.parse(res)); - return _this.roomStore.set(basicRoom.id, basicRoom); - }).catch(function (err) { - _this.logger.warn('error joining room ' + roomId + ':', err); - throw err; - }); - }; - - this.leaveRoom = function (roomId) { - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'POST', - path: '/users/' + _this.encodedId + '/rooms/' + roomId + '/leave' - }).then(function () { - return _this.roomStore.pop(roomId); - }).catch(function (err) { - _this.logger.warn('error leaving room ' + roomId + ':', err); - throw err; - }); - }; - - this.addUser = function (userId, roomId) { - typeCheck('userId', 'string', userId); - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'PUT', - path: '/rooms/' + roomId + '/users/add', - json: { - user_ids: [userId] - } - }).then(function () { - return _this.roomStore.addUserToRoom(roomId, userId); - }).catch(function (err) { - _this.logger.warn('error adding user ' + userId + ' to room ' + roomId + ':', err); - throw err; - }); - }; - - this.removeUser = function (userId, roomId) { - typeCheck('userId', 'string', userId); - typeCheck('roomId', 'number', roomId); - return _this.apiInstance.request({ - method: 'PUT', - path: '/rooms/' + roomId + '/users/remove', - json: { - user_ids: [userId] - } - }).then(function () { - return _this.roomStore.removeUserFromRoom(roomId, userId); - }).catch(function (err) { - _this.logger.warn('error removing user ' + userId + ' from room ' + roomId + ':', err); - throw err; - }); - }; - - this.sendMessage = function (_ref3) { - var text = _ref3.text, - roomId = _ref3.roomId, - attachment = _ref3.attachment; - - typeCheck('text', 'string', text); - typeCheck('roomId', 'number', roomId); - return new Promise(function (resolve, reject) { - if (attachment !== undefined && isDataAttachment(attachment)) { - resolve(_this.uploadDataAttachment(roomId, attachment)); - } else if (attachment !== undefined && isLinkAttachment(attachment)) { - resolve({ resource_link: attachment.link, type: attachment.type }); - } else if (attachment !== undefined) { - reject(new TypeError('attachment was malformed')); - } else { - resolve(); - } - }).then(function (attachment) { - return _this.apiInstance.request({ - method: 'POST', - path: '/rooms/' + roomId + '/messages', - json: { text: text, attachment: attachment } - }); - }).then(pipe(JSON.parse, prop('message_id'))).catch(function (err) { - _this.logger.warn('error sending message to room ' + roomId + ':', err); - throw err; - }); - }; - - this.fetchMessages = function (roomId) { - var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - initialId = _ref4.initialId, - limit = _ref4.limit, - direction = _ref4.direction; - - typeCheck('roomId', 'number', roomId); - initialId && typeCheck('initialId', 'number', initialId); - limit && typeCheck('limit', 'number', limit); - direction && checkOneOf('direction', ['older', 'newer'], direction); - return _this.apiInstance.request({ - method: 'GET', - path: '/rooms/' + roomId + '/messages?' + urlEncode({ - initial_id: initialId, - limit: limit, - direction: direction - }) - }).then(function (res) { - var messages = map(compose(_this.decorateMessage, parseBasicMessage), JSON.parse(res)); - return _this.userStore.fetchMissingUsers(uniq(map(prop('senderId'), messages))).then(function () { - return sort(function (x, y) { - return x.id - y.id; - }, messages); - }); - }).catch(function (err) { - _this.logger.warn('error fetching messages from room ' + roomId + ':', err); - throw err; - }); - }; - - this.subscribeToRoom = function (roomId) { - var hooks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var messageLimit = arguments[2]; - - typeCheck('roomId', 'number', roomId); - typeCheckObj('hooks', 'function', hooks); - messageLimit && typeCheck('messageLimit', 'number', messageLimit); - // TODO what is the desired behaviour if there is already a subscription to - // this room? Close the old one? Throw an error? Merge the hooks? - _this.roomSubscriptions[roomId] = new RoomSubscription({ - roomId: roomId, - hooks: hooks, - messageLimit: messageLimit, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - logger: _this.logger - }); - return _this.joinRoom(roomId).then(function (room) { - return _this.roomSubscriptions[roomId].connect().then(function () { - return room; - }); - }).catch(function (err) { - _this.logger.warn('error subscribing to room ' + roomId + ':', err); - throw err; - }); - }; - - this.fetchAttachment = function (url) { - return _this.filesInstance.tokenProvider.fetchToken().then(function (token) { - return pusherPlatform_4({ - method: 'GET', - headers: { Authorization: 'Bearer ' + token }, - url: url - }); - }).then(pipe(JSON.parse, parseFetchedAttachment)).catch(function (err) { - _this.logger.warn('error fetching attachment:', err); - throw err; - }); - }; - - this.uploadDataAttachment = function (roomId, _ref5) { - var file = _ref5.file, - name = _ref5.name; - - // TODO some validation on allowed file names? - // TODO polyfill FormData? - var body = new FormData(); // eslint-disable-line no-undef - body.append('file', file, name); - return _this.filesInstance.request({ - method: 'POST', - path: '/rooms/' + roomId + '/files/' + name, - body: body - }).then(JSON.parse); - }; - - this.isMemberOf = function (roomId) { - return contains$1(roomId, map(prop('id'), _this.rooms)); - }; - - this.decorateMessage = function (basicMessage) { - return new Message(basicMessage, _this.userStore, _this.roomStore); - }; - - this.establishUserSubscription = function (hooks) { - _this.userSubscription = new UserSubscription({ - hooks: hooks, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - typingIndicators: _this.typingIndicators, - roomSubscriptions: _this.roomSubscriptions - }); - return _this.userSubscription.connect().then(function (_ref6) { - var user = _ref6.user, - basicRooms = _ref6.basicRooms; - - _this.avatarURL = user.avatarURL; - _this.createdAt = user.createdAt; - _this.customData = user.customData; - _this.name = user.name; - _this.updatedAt = user.updatedAt; - _this.roomStore.initialize(indexBy(prop('id'), basicRooms)); - }).then(_this.initializeUserStore); - }; - - this.establishPresenceSubscription = function (hooks) { - _this.presenceSubscription = new PresenceSubscription({ - hooks: hooks, - userId: _this.id, - instance: _this.apiInstance, - userStore: _this.userStore, - roomStore: _this.roomStore, - presenceStore: _this.presenceStore, - roomSubscriptions: _this.roomSubscriptions - }); - return _this.presenceSubscription.connect(); - }; - - this.initializeUserStore = function () { - return _this.userStore.fetchMissingUsers(uniq(chain(prop('userIds'), _this.rooms))).catch(function (err) { - _this.logger.warn('error fetching initial user information:', err); - }).then(function () { - _this.userStore.initialize({}); - }); - }; - - this.id = id; - this.encodedId = encodeURIComponent(this.id); - this.apiInstance = apiInstance; - this.filesInstance = filesInstance; - this.logger = apiInstance.logger; - this.presenceStore = new Store(); - this.userStore = new UserStore({ - instance: this.apiInstance, - presenceStore: this.presenceStore, - logger: this.logger - }); - this.roomStore = new RoomStore({ - instance: this.apiInstance, - userStore: this.userStore, - logger: this.logger - }); - this.typingIndicators = new TypingIndicators({ - userId: this.id, - instance: this.apiInstance, - logger: this.logger - }); - this.roomSubscriptions = {}; - } - - /* public */ - - createClass(CurrentUser, [{ - key: 'rooms', - get: function get$$1() { - return values(this.roomStore.snapshot()); - } - }, { - key: 'users', - get: function get$$1() { - return values(this.userStore.snapshot()); - } - - /* internal */ - - }]); - return CurrentUser; -}(); - -var isDataAttachment = function isDataAttachment(_ref7) { - var file = _ref7.file, - name = _ref7.name; - - if (file === undefined || name === undefined) { - return false; - } - typeCheck('attachment.file', 'object', file); - typeCheck('attachment.name', 'string', name); - return true; -}; - -var isLinkAttachment = function isLinkAttachment(_ref8) { - var link = _ref8.link, - type = _ref8.type; - - if (link === undefined || type === undefined) { - return false; - } - typeCheck('attachment.link', 'string', link); - typeCheck('attachment.type', 'string', type); - return true; -}; - -var ChatManager = function ChatManager() { - var _this = this; - - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - var instanceLocator = _ref.instanceLocator, - tokenProvider = _ref.tokenProvider, - userId = _ref.userId, - options = objectWithoutProperties(_ref, ['instanceLocator', 'tokenProvider', 'userId']); - classCallCheck(this, ChatManager); - - this.connect = function () { - var hooks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - typeCheckObj('hooks', 'function', hooks); - var currentUser = new CurrentUser({ - id: _this.userId, - apiInstance: _this.apiInstance, - filesInstance: _this.filesInstance - }); - return Promise.all([currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) - // currentUser.initializeCursorStore() - ]).then(function () { - return currentUser; - }); - }; - - typeCheck('instanceLocator', 'string', instanceLocator); - typeCheck('tokenProvider', 'object', tokenProvider); - typeCheck('tokenProvider.fetchToken', 'function', tokenProvider.fetchToken); - typeCheck('userId', 'string', userId); - var cluster = split(':', instanceLocator)[1]; - if (cluster === undefined) { - throw new TypeError('expected instanceLocator to be of the format x:y:z, but was ' + instanceLocator); - } - var baseClient = options.baseClient || new pusherPlatform_1({ - host: cluster + '.' + pusherPlatform_2, - logger: options.logger - }); - if (typeof tokenProvider.setUserId === 'function') { - tokenProvider.setUserId(userId); - } - var instanceOptions = { - client: baseClient, - locator: instanceLocator, - logger: options.logger, - tokenProvider: tokenProvider - }; - this.apiInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit', - serviceVersion: 'v1' - }, instanceOptions)); - this.filesInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit_files', - serviceVersion: 'v1' - }, instanceOptions)); - this.cursorsInstance = new pusherPlatform_3(_extends({ - serviceName: 'chatkit_cursors', - serviceVersion: 'v1' - }, instanceOptions)); - this.userId = userId; -}; - -var main = { TokenProvider: TokenProvider, ChatManager: ChatManager }; - -return main; - -}))); diff --git a/package.json b/package.json index 01b3e43..8ec9110 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.6.2", + "version": "0.7.0-alpha", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From d1f0ad6902273d8bbf49b40ca4e4091574ee1dab Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 22 Feb 2018 15:26:02 +0000 Subject: [PATCH 61/99] data attachment tests --- tests/main.js | 63 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/tests/main.js b/tests/main.js index 2c3afe8..7558396 100644 --- a/tests/main.js +++ b/tests/main.js @@ -1,3 +1,5 @@ +/* eslint-env browser */ + import test from 'tape' import { any, @@ -19,7 +21,7 @@ import ChatkitServer from 'pusher-chatkit-server' import { TokenProvider, ChatManager } from '../dist/web/chatkit.js' import { INSTANCE_LOCATOR, INSTANCE_KEY, TOKEN_PROVIDER_URL } from './config' -let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom +let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom, dataAttachmentUrl const TEST_TIMEOUT = 15 * 1000 @@ -286,7 +288,7 @@ test('user came online hook (user sub)', t => { // TODO cancel methods so that we can do this, and because we should have them // anyway -test('typing indicators (user sub)', t => { +test.skip('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { @@ -665,11 +667,11 @@ test('send message with malformed attachment fails', t => { t.timeoutAfter(TEST_TIMEOUT) }) -test(`send message with link attachment [sends one message to Bob's room]`, t => { +test(`send message with link attachment [sends a message to Bob's room]`, t => { fetchUser(t, 'alice') .then(alice => alice.sendMessage({ roomId: bobsRoom.id, - text: 'see attached', + text: 'see attached link', attachment: { link: 'https://cataas.com/cat', type: 'image' } })) .then(() => t.end()) @@ -681,7 +683,7 @@ test('receive message with link attachment', t => { fetchUser(t, 'alice') .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 1 })) .then(([message]) => { - t.equal(message.text, 'see attached') + t.equal(message.text, 'see attached link') t.deepEqual(message.attachment, { link: 'https://cataas.com/cat', type: 'image', @@ -692,6 +694,55 @@ test('receive message with link attachment', t => { t.timeoutAfter(TEST_TIMEOUT) }) +test(`send message with data attachment [sends a message to Bob's room]`, t => { + fetchUser(t, 'alice') + .then(alice => alice.sendMessage({ + roomId: bobsRoom.id, + text: 'see attached json', + attachment: { + file: new File([JSON.stringify({ hello: 'world' })], { + type: 'application/json' + }), + name: 'hello.json' + } + })) + .then(() => t.end()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('receive message with data attachment', t => { + fetchUser(t, 'alice') + .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 1 })) + .then(([message]) => { + t.equal(message.text, 'see attached json') + t.equal(message.attachment.type, 'file') + t.equal(message.attachment.fetchRequired, true) + dataAttachmentUrl = message.attachment.link + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +// FIXME pending proper CORS headers being set up on the rich media S3 buckets +test.skip('fetch data attachment', t => { + fetchUser(t, 'alice') + .then(alice => alice.fetchAttachment(dataAttachmentUrl)) + .then(attachment => { + t.equal(attachment.file.name, 'hello.json') + t.equal(attachment.file.bytes, 17) + t.comment(attachment.link) + return fetch(attachment.link) + }) + .then(json => { + t.equal(json, '{"hello":"world"}') + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + test('[setup] create Carol', t => { server.createUser('carol', 'Carol') .then(() => server.createRoom('carol', { name: `Carol's room` })) @@ -759,7 +810,7 @@ test('user came online hook', t => { // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. -test('typing indicators', t => { +test.skip('typing indicators', t => { let started Promise.all([ fetchUser(t, 'alice') From 64e4e6103350255e2306a4aad36866e13f63509a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 23 Feb 2018 16:55:07 +0000 Subject: [PATCH 62/99] get and set cursors most basic implementation (fetch every time) --- .gitignore | 2 ++ src/chat-manager.js | 5 ++-- src/current-user.js | 50 ++++++++++++++++++++++++++++++++++++-- src/cursor.js | 19 +++++++++++++++ src/parsers.js | 8 +++++++ tests/main.js | 58 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/cursor.js diff --git a/.gitignore b/.gitignore index 0b5c187..205a088 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ yarn-error.log .DS_Store .vscode/ tests/config.js +tests/config.us1.js +tests/config.deneb.js diff --git a/src/chat-manager.js b/src/chat-manager.js index 60b386c..a6136b9 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -52,12 +52,13 @@ export class ChatManager { const currentUser = new CurrentUser({ id: this.userId, apiInstance: this.apiInstance, - filesInstance: this.filesInstance + filesInstance: this.filesInstance, + cursorsInstance: this.cursorsInstance }) return Promise.all([ currentUser.establishUserSubscription(hooks), currentUser.establishPresenceSubscription(hooks) - // currentUser.initializeCursorStore() + // currentUser.establishCursorsSubscription(hooks) ]).then(() => currentUser) } } diff --git a/src/current-user.js b/src/current-user.js index 9379db6..91a1f2d 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -23,6 +23,7 @@ import { import { parseBasicMessage, parseBasicRoom, + parseBasicCursor, parseFetchedAttachment } from './parsers' import { Store } from './store' @@ -33,13 +34,15 @@ import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' import { RoomSubscription } from './room-subscription' import { Message } from './message' +import { Cursor } from './cursor' export class CurrentUser { - constructor ({ id, apiInstance, filesInstance }) { + constructor ({ id, apiInstance, filesInstance, cursorsInstance }) { this.id = id this.encodedId = encodeURIComponent(this.id) this.apiInstance = apiInstance this.filesInstance = filesInstance + this.cursorsInstance = cursorsInstance this.logger = apiInstance.logger this.presenceStore = new Store() this.userStore = new UserStore({ @@ -70,7 +73,44 @@ export class CurrentUser { return values(this.userStore.snapshot()) } - isTypingIn = (roomId) => { + setReadCursor = (roomId, position) => { + typeCheck('roomId', 'number', roomId) + typeCheck('position', 'number', position) + return this.cursorsInstance + .request({ + method: 'PUT', + path: `/cursors/0/rooms/${roomId}/users/${this.encodedId}`, + json: { position } + }) + .then(() => {}) + .catch(err => { + this.logger.warn('error setting cursor:', err) + throw err + }) + } + + getReadCursor = (roomId, userId = this.id) => { + typeCheck('roomId', 'number', roomId) + typeCheck('userId', 'string', userId) + return this.cursorsInstance + .request({ + method: 'GET', + path: `/cursors/0/rooms/${roomId}/users/${encodeURIComponent(userId)}` + }) + .then(res => { + const data = JSON.parse(res) + if (data) { + return this.decorateCursor(parseBasicCursor(data)) + } + return undefined + }) + .catch(err => { + this.logger.warn('error getting cursor:', err) + throw err + }) + } + + isTypingIn = roomId => { typeCheck('roomId', 'number', roomId) return this.typingIndicators.sendThrottledRequest(roomId) } @@ -304,6 +344,12 @@ export class CurrentUser { this.roomStore ) + decorateCursor = basicCursor => new Cursor( + basicCursor, + this.userStore, + this.roomStore + ) + establishUserSubscription = hooks => { this.userSubscription = new UserSubscription({ hooks, diff --git a/src/cursor.js b/src/cursor.js new file mode 100644 index 0000000..d4f2458 --- /dev/null +++ b/src/cursor.js @@ -0,0 +1,19 @@ +export class Cursor { + constructor (basicCursor, userStore, roomStore) { + this.position = basicCursor.position + this.updatedAt = basicCursor.updatedAt + this.userId = basicCursor.userId + this.roomId = basicCursor.roomId + this.cursorType = basicCursor.cursorType + this.userStore = userStore + this.roomStore = roomStore + } + + get user () { + return this.userStore.getSync(this.userId) + } + + get room () { + return this.roomStore.getSync(this.roomId) + } +} diff --git a/src/parsers.js b/src/parsers.js index 026e043..cc3726f 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -48,6 +48,14 @@ export const parseFetchedAttachment = data => ({ ttl: data.ttl }) +export const parseBasicCursor = data => ({ + position: data.position, + updatedAt: data.updated_at, + userId: data.user_id, + roomId: data.room_id, + cursorType: data.cursor_type +}) + const parseMessageAttachment = data => ({ link: data.resource_link, type: data.type, diff --git a/tests/main.js b/tests/main.js index 7558396..4b27255 100644 --- a/tests/main.js +++ b/tests/main.js @@ -653,6 +653,8 @@ test('subscribe to room and receive sent messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) +// Attachments + test('send message with malformed attachment fails', t => { fetchUser(t, 'alice') .then(alice => alice.sendMessage({ @@ -856,6 +858,62 @@ test(`user left hook [removes Carol from Bob's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) +// Cursors + +test('own read cursor undefined if not set', t => { + fetchUser(t, 'alice') + .then(alice => alice.getReadCursor(alicesRoom.id)) + .then(cursor => { + t.equal(cursor, undefined) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('set own read cursor [Alice sets her read cursor in her room]', t => { + fetchUser(t, 'alice') + .then(alice => alice.setReadCursor(alicesRoom.id, 42)) + .then(t.end) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('get own read cursor', t => { + fetchUser(t, 'alice') + .then(alice => alice.getReadCursor(alicesRoom.id)) + .then(cursor => { + t.equal(cursor.position, 42) + t.equal(cursor.user.name, 'Alice') + t.equal(cursor.room.name, `Alice's new room`) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test(`setup [Bob sets his read cursor in Alice's room]`, t => { + fetchUser(t, 'bob') + .then(bob => bob.joinRoom(alicesRoom.id).then(() => bob)) + .then(bob => bob.setReadCursor(alicesRoom.id, 128)) + .then(t.end) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test(`get another user's read cursor`, t => { + fetchUser(t, 'alice') + .then(alice => alice.getReadCursor(alicesRoom.id, 'bob')) + .then(cursor => { + t.equal(cursor.position, 128) + t.equal(cursor.user.name, 'Bob') + t.equal(cursor.room.name, `Alice's new room`) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + // FIXME test.skip('non-admin update room fails gracefully', t => { fetchUser(t, 'alice').then(alice => alice.updateRoom( From c81f5feccbab6efb3177d5304d9430bb81fd265f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 26 Feb 2018 14:46:05 +0000 Subject: [PATCH 63/99] cursor store --- src/current-user.js | 29 ++++++++----------------- src/cursor-store.js | 53 +++++++++++++++++++++++++++++++++++++++++++++ src/user-store.js | 2 +- 3 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 src/cursor-store.js diff --git a/src/current-user.js b/src/current-user.js index 91a1f2d..473fb6c 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -23,18 +23,17 @@ import { import { parseBasicMessage, parseBasicRoom, - parseBasicCursor, parseFetchedAttachment } from './parsers' import { Store } from './store' import { UserStore } from './user-store' import { RoomStore } from './room-store' +import { CursorStore } from './cursor-store' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' import { RoomSubscription } from './room-subscription' import { Message } from './message' -import { Cursor } from './cursor' export class CurrentUser { constructor ({ id, apiInstance, filesInstance, cursorsInstance }) { @@ -55,6 +54,13 @@ export class CurrentUser { userStore: this.userStore, logger: this.logger }) + this.cursorStore = new CursorStore({ + instance: this.cursorsInstance, + userStore: this.userStore, + roomStore: this.roomStore, + logger: this.logger + }) + this.cursorStore.initialize({}) // TODO remove this.typingIndicators = new TypingIndicators({ userId: this.id, instance: this.apiInstance, @@ -92,18 +98,7 @@ export class CurrentUser { getReadCursor = (roomId, userId = this.id) => { typeCheck('roomId', 'number', roomId) typeCheck('userId', 'string', userId) - return this.cursorsInstance - .request({ - method: 'GET', - path: `/cursors/0/rooms/${roomId}/users/${encodeURIComponent(userId)}` - }) - .then(res => { - const data = JSON.parse(res) - if (data) { - return this.decorateCursor(parseBasicCursor(data)) - } - return undefined - }) + return this.cursorStore.get(userId, roomId) .catch(err => { this.logger.warn('error getting cursor:', err) throw err @@ -344,12 +339,6 @@ export class CurrentUser { this.roomStore ) - decorateCursor = basicCursor => new Cursor( - basicCursor, - this.userStore, - this.roomStore - ) - establishUserSubscription = hooks => { this.userSubscription = new UserSubscription({ hooks, diff --git a/src/cursor-store.js b/src/cursor-store.js new file mode 100644 index 0000000..d50b2d6 --- /dev/null +++ b/src/cursor-store.js @@ -0,0 +1,53 @@ +import { Store } from './store' +import { Cursor } from './cursor' +import { parseBasicCursor } from './parsers' + +export class CursorStore { + constructor ({ instance, userStore, roomStore, logger }) { + this.instance = instance + this.userStore = userStore + this.roomStore = roomStore + this.logger = logger + } + + store = new Store() + + initialize = this.store.initialize + + set = (userId, roomId, cursor) => this.store.set(key(userId, roomId), cursor) + + get = (userId, roomId) => { + return this.store.get(key(userId, roomId)) + .then(cursor => cursor || this.fetchBasicCursor(userId, roomId) + .then(cursor => this.set(userId, roomId, cursor)) + ) + .then(this.decorate) + } + + fetchBasicCursor = (userId, roomId) => { + return this.instance + .request({ + method: 'GET', + path: `/cursors/0/rooms/${roomId}/users/${encodeURIComponent(userId)}` + }) + .then(res => { + const data = JSON.parse(res) + if (data) { + return this.decorate(parseBasicCursor(data)) + } + return undefined + }) + .catch(err => { + this.logger.warn('error fetching cursor:', err) + throw err + }) + } + + decorate = basicCursor => { + return basicCursor + ? new Cursor(basicCursor, this.userStore, this.roomStore) + : undefined + } +} + +const key = (userId, roomId) => `${userId}/${roomId}` diff --git a/src/user-store.js b/src/user-store.js index 731d4eb..9748477 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -13,6 +13,7 @@ import { appendQueryParam } from './utils' import { Store } from './store' import { parseUser } from './parsers' +// TODO user object decorated by presence store export class UserStore { constructor ({ instance, presenceStore, logger }) { this.instance = instance @@ -44,7 +45,6 @@ export class UserStore { }) .catch(err => { this.logger.warn('error fetching user information:', err) - throw err }) } From 11d9b0c334a5046cf8dbf9957d889c466fcb8a3a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 26 Feb 2018 15:01:54 +0000 Subject: [PATCH 64/99] user object for symmetry with rooms, cursors, messages etc --- src/parsers.js | 2 +- src/user-store.js | 19 ++++++++++--------- src/user-subscription.js | 4 ++-- src/user.js | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 src/user.js diff --git a/src/parsers.js b/src/parsers.js index cc3726f..a75a75a 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -13,7 +13,7 @@ export const parseBasicRoom = data => ({ userIds: data.member_user_ids }) -export const parseUser = data => ({ +export const parseBasicUser = data => ({ avatarURL: data.avatar_url, createdAt: data.created_at, customData: data.custom_data, diff --git a/src/user-store.js b/src/user-store.js index 9748477..f9dc7c9 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -11,9 +11,9 @@ import { import { appendQueryParam } from './utils' import { Store } from './store' -import { parseUser } from './parsers' +import { parseBasicUser } from './parsers' +import { User } from './user' -// TODO user object decorated by presence store export class UserStore { constructor ({ instance, presenceStore, logger }) { this.instance = instance @@ -29,8 +29,8 @@ export class UserStore { get = userId => Promise.all([ this.store.get(userId).then(user => user || this.fetchBasicUser(userId)), - this.presenceStore.get(userId) - ]).then(([user, presence]) => ({ ...user, presence })) + this.presenceStore.get(userId) // Make sure it's safe to getSync + ]).then(([user, presence]) => this.decorate(user)) fetchBasicUser = userId => { return this.instance @@ -39,12 +39,13 @@ export class UserStore { path: `/users/${encodeURIComponent(userId)}` }) .then(res => { - const user = parseUser(JSON.parse(res)) + const user = parseBasicUser(JSON.parse(res)) this.set(userId, user) return user }) .catch(err => { this.logger.warn('error fetching user information:', err) + throw err }) } @@ -66,7 +67,7 @@ export class UserStore { }) .then(pipe( JSON.parse, - map(parseUser), + map(parseBasicUser), forEach(user => this.set(user.id, user)) )) .catch(err => { @@ -79,9 +80,9 @@ export class UserStore { getSync = userId => this.decorate(this.store.getSync(userId)) - decorate = user => { - return user - ? { ...user, presence: this.presenceStore.getSync(user.id) } + decorate = basicUser => { + return basicUser + ? new User(basicUser, this.presenceStore) : undefined } } diff --git a/src/user-subscription.js b/src/user-subscription.js index 98d5a91..71b2ea0 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -1,6 +1,6 @@ import { map, prop } from 'ramda' -import { parseBasicRoom, parseUser } from './parsers' +import { parseBasicRoom, parseBasicUser } from './parsers' export class UserSubscription { constructor (options) { @@ -57,7 +57,7 @@ export class UserSubscription { onInitialState = ({ current_user: userData, rooms: roomsData }) => { this.hooks.subscriptionEstablished({ - user: parseUser(userData), + user: parseBasicUser(userData), basicRooms: map(parseBasicRoom, roomsData) }) } diff --git a/src/user.js b/src/user.js new file mode 100644 index 0000000..df61e73 --- /dev/null +++ b/src/user.js @@ -0,0 +1,15 @@ +export class User { + constructor (basicUser, presenceStore) { + this.avatarURL = basicUser.avatarURL + this.createdAt = basicUser.createdAt + this.customData = basicUser.customData + this.id = basicUser.id + this.name = basicUser.name + this.updatedAt = basicUser.updatedAt + this.presenceStore = presenceStore + } + + get presence () { + return this.presenceStore.getSync(this.id) + } +} From 3db62420f1746d9025820f764dbef2ccf189f0de Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 26 Feb 2018 16:21:28 +0000 Subject: [PATCH 65/99] new read cursor hook (own cursors) --- src/chat-manager.js | 4 +-- src/current-user.js | 22 +++++++++++- src/cursor-subscription.js | 42 ++++++++++++++++++++++ src/cursor.js | 2 +- src/parsers.js | 2 +- tests/main.js | 72 +++++++++++++++++++++----------------- 6 files changed, 107 insertions(+), 37 deletions(-) create mode 100644 src/cursor-subscription.js diff --git a/src/chat-manager.js b/src/chat-manager.js index a6136b9..6062fe0 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -57,8 +57,8 @@ export class ChatManager { }) return Promise.all([ currentUser.establishUserSubscription(hooks), - currentUser.establishPresenceSubscription(hooks) - // currentUser.establishCursorsSubscription(hooks) + currentUser.establishPresenceSubscription(hooks), + currentUser.establishCursorSubscription(hooks) ]).then(() => currentUser) } } diff --git a/src/current-user.js b/src/current-user.js index 473fb6c..facf6d8 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -32,6 +32,7 @@ import { CursorStore } from './cursor-store' import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' +import { CursorSubscription } from './cursor-subscription' import { RoomSubscription } from './room-subscription' import { Message } from './message' @@ -60,7 +61,6 @@ export class CurrentUser { roomStore: this.roomStore, logger: this.logger }) - this.cursorStore.initialize({}) // TODO remove this.typingIndicators = new TypingIndicators({ userId: this.id, instance: this.apiInstance, @@ -372,6 +372,26 @@ export class CurrentUser { return this.presenceSubscription.connect() } + establishCursorSubscription = hooks => { + this.cursorSubscription = new CursorSubscription({ + hooks: { + newCursor: cursor => { + if ( + hooks.newReadCursor && cursor.type === 0 && + this.isMemberOf(cursor.roomId) + ) { + hooks.newReadCursor(cursor) + } + } + }, + path: `/cursors/0/users/${this.encodedId}`, + cursorStore: this.cursorStore, + instance: this.cursorsInstance + }) + return this.cursorSubscription.connect() + .then(() => this.cursorStore.initialize({})) + } + initializeUserStore = () => { return this.userStore.fetchMissingUsers( uniq(chain(prop('userIds'), this.rooms)) diff --git a/src/cursor-subscription.js b/src/cursor-subscription.js new file mode 100644 index 0000000..ffc54d8 --- /dev/null +++ b/src/cursor-subscription.js @@ -0,0 +1,42 @@ +import { parseBasicCursor } from './parsers' + +export class CursorSubscription { + constructor ({ hooks, path, cursorStore, instance }) { + this.hooks = hooks + this.path = path + this.cursorStore = cursorStore + this.instance = instance + } + + connect () { + return new Promise((resolve, reject) => { + this.instance.subscribeNonResuming({ + path: this.path, + listeners: { + onOpen: resolve, + onError: reject, + onEvent: this.onEvent + } + }) + }) + } + + onEvent = ({ body }) => { + switch (body.event_name) { + case 'cursor_set': + this.onCursorSet(body.data) + break + } + } + + onCursorSet = data => { + const basicCursor = parseBasicCursor(data) + this.cursorStore.set(basicCursor.userId, basicCursor.roomId, basicCursor) + .then(() => { + if (this.hooks.newCursor) { + this.cursorStore.get(basicCursor.userId, basicCursor.roomId) + .then(cursor => this.hooks.newCursor(cursor)) + } + }) + } +} diff --git a/src/cursor.js b/src/cursor.js index d4f2458..236408d 100644 --- a/src/cursor.js +++ b/src/cursor.js @@ -4,7 +4,7 @@ export class Cursor { this.updatedAt = basicCursor.updatedAt this.userId = basicCursor.userId this.roomId = basicCursor.roomId - this.cursorType = basicCursor.cursorType + this.type = basicCursor.type this.userStore = userStore this.roomStore = roomStore } diff --git a/src/parsers.js b/src/parsers.js index a75a75a..e0c0fbc 100644 --- a/src/parsers.js +++ b/src/parsers.js @@ -53,7 +53,7 @@ export const parseBasicCursor = data => ({ updatedAt: data.updated_at, userId: data.user_id, roomId: data.room_id, - cursorType: data.cursor_type + type: data.cursor_type }) const parseMessageAttachment = data => ({ diff --git a/tests/main.js b/tests/main.js index 4b27255..e167acf 100644 --- a/tests/main.js +++ b/tests/main.js @@ -240,6 +240,46 @@ test('connection resolves with current user object', t => { // User subscription +test('own read cursor undefined if not set', t => { + fetchUser(t, 'alice') + .then(alice => alice.getReadCursor(alicesRoom.id)) + .then(cursor => { + t.equal(cursor, undefined) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('new read cursor hook [Alice sets her read cursor in her room]', t => { + Promise.all([fetchUser(t, 'alice'), fetchUser(t, 'alice', { + newReadCursor: cursor => { + t.equal(cursor.position, 42) + t.equal(cursor.user.name, 'Alice') + t.equal(cursor.room.name, `Alice's room`) + t.end() + } + })]) + .then(([mobileAlice, browserAlice]) => + mobileAlice.setReadCursor(alicesRoom.id, 42) + ) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('get own read cursor', t => { + fetchUser(t, 'alice') + .then(alice => alice.getReadCursor(alicesRoom.id)) + .then(cursor => { + t.equal(cursor.position, 42) + t.equal(cursor.user.name, 'Alice') + t.equal(cursor.room.name, `Alice's room`) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + test(`added to room hook [creates Bob & Bob's room]`, t => { let alice fetchUser(t, 'alice', { @@ -860,38 +900,6 @@ test(`user left hook [removes Carol from Bob's room]`, t => { // Cursors -test('own read cursor undefined if not set', t => { - fetchUser(t, 'alice') - .then(alice => alice.getReadCursor(alicesRoom.id)) - .then(cursor => { - t.equal(cursor, undefined) - t.end() - }) - .catch(endWithErr(t)) - t.timeoutAfter(TEST_TIMEOUT) -}) - -test('set own read cursor [Alice sets her read cursor in her room]', t => { - fetchUser(t, 'alice') - .then(alice => alice.setReadCursor(alicesRoom.id, 42)) - .then(t.end) - .catch(endWithErr(t)) - t.timeoutAfter(TEST_TIMEOUT) -}) - -test('get own read cursor', t => { - fetchUser(t, 'alice') - .then(alice => alice.getReadCursor(alicesRoom.id)) - .then(cursor => { - t.equal(cursor.position, 42) - t.equal(cursor.user.name, 'Alice') - t.equal(cursor.room.name, `Alice's new room`) - t.end() - }) - .catch(endWithErr(t)) - t.timeoutAfter(TEST_TIMEOUT) -}) - test(`setup [Bob sets his read cursor in Alice's room]`, t => { fetchUser(t, 'bob') .then(bob => bob.joinRoom(alicesRoom.id).then(() => bob)) From ffc4a295f7d34d1c034e0126c188b6f85963ebbd Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 26 Feb 2018 16:52:53 +0000 Subject: [PATCH 66/99] room level cursor subscriptions --- src/current-user.js | 21 ++++++++++++++++++++- tests/main.js | 22 +++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index facf6d8..2f595ff 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -67,6 +67,7 @@ export class CurrentUser { logger: this.logger }) this.roomSubscriptions = {} + this.roomLevelCursorSubscriptions = {} } /* public */ @@ -294,8 +295,26 @@ export class CurrentUser { roomStore: this.roomStore, logger: this.logger }) + this.roomLevelCursorSubscriptions[roomId] = new CursorSubscription({ + hooks: { + newCursor: cursor => { + if ( + hooks.newReadCursor && cursor.type === 0 && + cursor.userId !== this.id + ) { + hooks.newReadCursor(cursor) + } + } + }, + path: `/cursors/0/rooms/${roomId}`, + cursorStore: this.cursorStore, + instance: this.cursorsInstance + }) return this.joinRoom(roomId) - .then(room => this.roomSubscriptions[roomId].connect().then(() => room)) + .then(room => Promise.all([ + this.roomSubscriptions[roomId].connect(), + this.roomLevelCursorSubscriptions[roomId].connect() + ]).then(() => room)) .catch(err => { this.logger.warn(`error subscribing to room ${roomId}:`, err) throw err diff --git a/tests/main.js b/tests/main.js index e167acf..64b82e9 100644 --- a/tests/main.js +++ b/tests/main.js @@ -900,11 +900,23 @@ test(`user left hook [removes Carol from Bob's room]`, t => { // Cursors -test(`setup [Bob sets his read cursor in Alice's room]`, t => { - fetchUser(t, 'bob') - .then(bob => bob.joinRoom(alicesRoom.id).then(() => bob)) - .then(bob => bob.setReadCursor(alicesRoom.id, 128)) - .then(t.end) +test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { + Promise.all([ + fetchUser(t, 'bob') + .then(bob => bob.joinRoom(alicesRoom.id).then(() => bob)), + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(alicesRoom.id, { + newReadCursor: cursor => { + t.equal(cursor.position, 128) + t.equal(cursor.user.name, 'Bob') + t.equal(cursor.room.name, `Alice's new room`) + t.end() + } + })) + ]) + .then(([bob]) => + bob.setReadCursor(alicesRoom.id, 128) + ) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) From eca115166f0eeed7dc73f0ee813d3dd5bcfebfe9 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 26 Feb 2018 17:26:51 +0000 Subject: [PATCH 67/99] sync readCursor --- src/current-user.js | 8 ++------ src/cursor-store.js | 4 ++++ tests/main.js | 13 ++++++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 2f595ff..e919fd1 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -96,14 +96,10 @@ export class CurrentUser { }) } - getReadCursor = (roomId, userId = this.id) => { + readCursor = (roomId, userId = this.id) => { typeCheck('roomId', 'number', roomId) typeCheck('userId', 'string', userId) - return this.cursorStore.get(userId, roomId) - .catch(err => { - this.logger.warn('error getting cursor:', err) - throw err - }) + return this.cursorStore.getSync(userId, roomId) } isTypingIn = roomId => { diff --git a/src/cursor-store.js b/src/cursor-store.js index d50b2d6..2d0d55a 100644 --- a/src/cursor-store.js +++ b/src/cursor-store.js @@ -24,6 +24,10 @@ export class CursorStore { .then(this.decorate) } + getSync = (userId, roomId) => { + return this.decorate(this.store.getSync(key(userId, roomId))) + } + fetchBasicCursor = (userId, roomId) => { return this.instance .request({ diff --git a/tests/main.js b/tests/main.js index 64b82e9..200d785 100644 --- a/tests/main.js +++ b/tests/main.js @@ -242,9 +242,8 @@ test('connection resolves with current user object', t => { test('own read cursor undefined if not set', t => { fetchUser(t, 'alice') - .then(alice => alice.getReadCursor(alicesRoom.id)) - .then(cursor => { - t.equal(cursor, undefined) + .then(alice => { + t.equal(alice.readCursor(alicesRoom.id), undefined) t.end() }) .catch(endWithErr(t)) @@ -269,8 +268,8 @@ test('new read cursor hook [Alice sets her read cursor in her room]', t => { test('get own read cursor', t => { fetchUser(t, 'alice') - .then(alice => alice.getReadCursor(alicesRoom.id)) - .then(cursor => { + .then(alice => { + const cursor = alice.readCursor(alicesRoom.id) t.equal(cursor.position, 42) t.equal(cursor.user.name, 'Alice') t.equal(cursor.room.name, `Alice's room`) @@ -923,8 +922,8 @@ test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { test(`get another user's read cursor`, t => { fetchUser(t, 'alice') - .then(alice => alice.getReadCursor(alicesRoom.id, 'bob')) - .then(cursor => { + .then(alice => { + const cursor = alice.readCursor(alicesRoom.id, 'bob') t.equal(cursor.position, 128) t.equal(cursor.user.name, 'Bob') t.equal(cursor.room.name, `Alice's new room`) From ae2e4333be395cafb5453f1549cac7422f5acf0e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 27 Feb 2018 16:46:16 +0000 Subject: [PATCH 68/99] initial_state --- src/current-user.js | 34 +++++++++++++++++++++++----------- src/cursor-subscription.js | 15 ++++++++++++++- tests/main.js | 23 ++++++++++------------- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index e919fd1..dd30141 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -364,14 +364,20 @@ export class CurrentUser { typingIndicators: this.typingIndicators, roomSubscriptions: this.roomSubscriptions }) - return this.userSubscription.connect().then(({ user, basicRooms }) => { - this.avatarURL = user.avatarURL - this.createdAt = user.createdAt - this.customData = user.customData - this.name = user.name - this.updatedAt = user.updatedAt - this.roomStore.initialize(indexBy(prop('id'), basicRooms)) - }).then(this.initializeUserStore) + return this.userSubscription.connect() + .then(({ user, basicRooms }) => { + this.avatarURL = user.avatarURL + this.createdAt = user.createdAt + this.customData = user.customData + this.name = user.name + this.updatedAt = user.updatedAt + this.roomStore.initialize(indexBy(prop('id'), basicRooms)) + }) + .then(this.initializeUserStore) + .catch(err => { + this.logger.error('error establishing user subscription:', err) + throw err + }) } establishPresenceSubscription = hooks => { @@ -385,6 +391,10 @@ export class CurrentUser { roomSubscriptions: this.roomSubscriptions }) return this.presenceSubscription.connect() + .catch(err => { + this.logger.warn('error establishing presence subscription:', err) + throw err + }) } establishCursorSubscription = hooks => { @@ -405,6 +415,10 @@ export class CurrentUser { }) return this.cursorSubscription.connect() .then(() => this.cursorStore.initialize({})) + .catch(err => { + this.logger.warn('error establishing cursor subscription:', err) + throw err + }) } initializeUserStore = () => { @@ -414,9 +428,7 @@ export class CurrentUser { .catch(err => { this.logger.warn('error fetching initial user information:', err) }) - .then(() => { - this.userStore.initialize({}) - }) + .then(() => this.userStore.initialize({})) } } diff --git a/src/cursor-subscription.js b/src/cursor-subscription.js index ffc54d8..5fb9fc5 100644 --- a/src/cursor-subscription.js +++ b/src/cursor-subscription.js @@ -1,3 +1,5 @@ +import { compose, forEach, map } from 'ramda' + import { parseBasicCursor } from './parsers' export class CursorSubscription { @@ -10,10 +12,10 @@ export class CursorSubscription { connect () { return new Promise((resolve, reject) => { + this.hooks = { ...this.hooks, subscriptionEstablished: resolve } this.instance.subscribeNonResuming({ path: this.path, listeners: { - onOpen: resolve, onError: reject, onEvent: this.onEvent } @@ -23,12 +25,23 @@ export class CursorSubscription { onEvent = ({ body }) => { switch (body.event_name) { + case 'initial_state': + this.onInitialState(body.data) + break case 'cursor_set': this.onCursorSet(body.data) break } } + onInitialState = ({ cursors }) => { + compose( + forEach(c => this.cursorStore.set(c.userId, c.roomId, c)), + map(parseBasicCursor) + )(cursors) + this.hooks.subscriptionEstablished() + } + onCursorSet = data => { const basicCursor = parseBasicCursor(data) this.cursorStore.set(basicCursor.userId, basicCursor.roomId, basicCursor) diff --git a/tests/main.js b/tests/main.js index 200d785..0da5e2f 100644 --- a/tests/main.js +++ b/tests/main.js @@ -58,12 +58,10 @@ const batch = (n, f) => { const concatBatch = (n, f) => batch(n, compose(f, reduce(concat, []))) -const tokenProvider = new TokenProvider({ url: TOKEN_PROVIDER_URL }) - const fetchUser = (t, userId, hooks = {}) => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId, - tokenProvider, + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }), logger: { error: console.log, warn: console.log, @@ -130,7 +128,7 @@ test('instantiate ChatManager with correct params', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }) t.equal(typeof chatManager, 'object') t.equal(typeof chatManager.connect, 'function') @@ -141,7 +139,7 @@ test('instantiate ChatManager with non-string instanceLocator fails', t => { t.throws(() => new ChatManager({ instanceLocator: 42, userId: 'alice', - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }), /instanceLocator/) t.end() }) @@ -150,7 +148,7 @@ test('instantiate ChatManager without userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }), /userId/) t.end() }) @@ -159,7 +157,7 @@ test('instantiate ChatManager with non-string userId fails', t => { t.throws(() => new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 42, - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }), /string/) t.end() }) @@ -177,7 +175,7 @@ test('connection fails if provided with non-function hooks', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }) t.throws( () => chatManager.connect({ nonFunction: 42 }), @@ -190,7 +188,7 @@ test('connection fails for nonexistent user', t => { const chatManager = new ChatManager({ instanceLocator: INSTANCE_LOCATOR, userId: 'alice', - tokenProvider + tokenProvider: new TokenProvider({ url: TOKEN_PROVIDER_URL }) }) chatManager.connect() .then(() => { @@ -913,15 +911,14 @@ test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { } })) ]) - .then(([bob]) => - bob.setReadCursor(alicesRoom.id, 128) - ) + .then(([bob]) => bob.setReadCursor(alicesRoom.id, 128)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -test(`get another user's read cursor`, t => { +test(`get another user's read cursor after subscribing to a room`, t => { fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(alicesRoom.id).then(() => alice)) .then(alice => { const cursor = alice.readCursor(alicesRoom.id, 'bob') t.equal(cursor.position, 128) From c8a8b188037b26042c6a0a039b1593ee12c1881a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 28 Feb 2018 15:00:18 +0000 Subject: [PATCH 69/99] cursor_set -> new_cursor --- src/cursor-subscription.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cursor-subscription.js b/src/cursor-subscription.js index 5fb9fc5..c13ae8c 100644 --- a/src/cursor-subscription.js +++ b/src/cursor-subscription.js @@ -28,8 +28,8 @@ export class CursorSubscription { case 'initial_state': this.onInitialState(body.data) break - case 'cursor_set': - this.onCursorSet(body.data) + case 'new_cursor': + this.onNewCursor(body.data) break } } @@ -42,7 +42,7 @@ export class CursorSubscription { this.hooks.subscriptionEstablished() } - onCursorSet = data => { + onNewCursor = data => { const basicCursor = parseBasicCursor(data) this.cursorStore.set(basicCursor.userId, basicCursor.roomId, basicCursor) .then(() => { From 79087a2585f778c0f1984847cb5537ee381a7bbc Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 28 Feb 2018 15:32:24 +0000 Subject: [PATCH 70/99] bundle the message and cursor sub together as a "room sub" (and rename room sub to message sub) --- src/current-user.js | 56 ++++++++++--------- ...ubscription.js => message-subscription.js} | 2 +- src/presence-subscription.js | 8 +-- 3 files changed, 34 insertions(+), 32 deletions(-) rename src/{room-subscription.js => message-subscription.js} (98%) diff --git a/src/current-user.js b/src/current-user.js index dd30141..7fc2415 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -33,7 +33,7 @@ import { TypingIndicators } from './typing-indicators' import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' import { CursorSubscription } from './cursor-subscription' -import { RoomSubscription } from './room-subscription' +import { MessageSubscription } from './message-subscription' import { Message } from './message' export class CurrentUser { @@ -67,7 +67,6 @@ export class CurrentUser { logger: this.logger }) this.roomSubscriptions = {} - this.roomLevelCursorSubscriptions = {} } /* public */ @@ -281,35 +280,38 @@ export class CurrentUser { messageLimit && typeCheck('messageLimit', 'number', messageLimit) // TODO what is the desired behaviour if there is already a subscription to // this room? Close the old one? Throw an error? Merge the hooks? - this.roomSubscriptions[roomId] = new RoomSubscription({ - roomId, + this.roomSubscriptions[roomId] = { hooks, - messageLimit, - userId: this.id, - instance: this.apiInstance, - userStore: this.userStore, - roomStore: this.roomStore, - logger: this.logger - }) - this.roomLevelCursorSubscriptions[roomId] = new CursorSubscription({ - hooks: { - newCursor: cursor => { - if ( - hooks.newReadCursor && cursor.type === 0 && - cursor.userId !== this.id - ) { - hooks.newReadCursor(cursor) + messageSub: new MessageSubscription({ + roomId, + hooks, + messageLimit, + userId: this.id, + instance: this.apiInstance, + userStore: this.userStore, + roomStore: this.roomStore, + logger: this.logger + }), + cursorSub: new CursorSubscription({ + hooks: { + newCursor: cursor => { + if ( + hooks.newReadCursor && cursor.type === 0 && + cursor.userId !== this.id + ) { + hooks.newReadCursor(cursor) + } } - } - }, - path: `/cursors/0/rooms/${roomId}`, - cursorStore: this.cursorStore, - instance: this.cursorsInstance - }) + }, + path: `/cursors/0/rooms/${roomId}`, + cursorStore: this.cursorStore, + instance: this.cursorsInstance + }) + } return this.joinRoom(roomId) .then(room => Promise.all([ - this.roomSubscriptions[roomId].connect(), - this.roomLevelCursorSubscriptions[roomId].connect() + this.roomSubscriptions[roomId].messageSub.connect(), + this.roomSubscriptions[roomId].cursorSub.connect() ]).then(() => room)) .catch(err => { this.logger.warn(`error subscribing to room ${roomId}:`, err) diff --git a/src/room-subscription.js b/src/message-subscription.js similarity index 98% rename from src/room-subscription.js rename to src/message-subscription.js index d77343a..81e0b4e 100644 --- a/src/room-subscription.js +++ b/src/message-subscription.js @@ -4,7 +4,7 @@ import { parseBasicMessage } from './parsers' import { urlEncode } from './utils' import { Message } from './message' -export class RoomSubscription { +export class MessageSubscription { constructor (options) { this.roomId = options.roomId this.hooks = options.hooks diff --git a/src/presence-subscription.js b/src/presence-subscription.js index dabb4ce..fe42d67 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -6,7 +6,7 @@ import { indexBy, map, prop, - values + toPairs } from 'ramda' import { parsePresence } from './parsers' @@ -87,13 +87,13 @@ export class PresenceSubscription { this.hooks[hookName](user) } compose( - forEach(sub => this.roomStore.get(sub.roomId).then(room => { + forEach(([roomId, sub]) => this.roomStore.get(roomId).then(room => { if (contains(user.id, room.userIds)) { sub.hooks[hookName](user) } })), - filter(sub => sub.hooks[hookName] !== undefined), - values + filter(([roomId, sub]) => sub.hooks[hookName] !== undefined), + toPairs )(this.roomSubscriptions) } } From 25a7a91f13e1917fab3a96ef9bd53a283cca1a91 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 1 Mar 2018 11:13:50 +0000 Subject: [PATCH 71/99] throw an error if readCursors is used to get another's cursor before subscribing to a room --- src/current-user.js | 8 ++++++++ tests/main.js | 30 ++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 7fc2415..d2b9736 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -4,6 +4,7 @@ import { compose, concat, contains, + has, indexBy, map, pipe, @@ -98,6 +99,13 @@ export class CurrentUser { readCursor = (roomId, userId = this.id) => { typeCheck('roomId', 'number', roomId) typeCheck('userId', 'string', userId) + if (userId !== this.id && !has(roomId, this.roomSubscriptions)) { + const err = new TypeError( + `Must be subscribed to room ${roomId} to access member's read cursors` + ) + this.logger.error(err) + throw err + } return this.cursorStore.getSync(userId, roomId) } diff --git a/tests/main.js b/tests/main.js index 0da5e2f..19f00cf 100644 --- a/tests/main.js +++ b/tests/main.js @@ -325,7 +325,7 @@ test('user came online hook (user sub)', t => { // TODO cancel methods so that we can do this, and because we should have them // anyway -test.skip('typing indicators (user sub)', t => { +test('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { @@ -343,10 +343,10 @@ test.skip('typing indicators (user sub)', t => { }), fetchUser(t, 'bob') ]) - // FIXME This test (and the corresponding room sub one) occasionally fail if - // isTypingIn is called without this timeout. It would seem that there is a - // race condition *somewhere*. - .then(([alice, bob]) => setTimeout(() => bob.isTypingIn(bobsRoom.id), 1000)) + // FIXME This test (and the corresponding room sub one) fail intermittently. + // The corresponding server side test fails too so there might be some kind + // of race condition in the server. Needs more investigation. + .then(([alice, bob]) => bob.isTypingIn(bobsRoom.id)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -849,7 +849,7 @@ test('user came online hook', t => { // We can't easily test for the user going offline, because the presence // subscription in the above test hangs around until it is garbage collected. -test.skip('typing indicators', t => { +test('typing indicators', t => { let started Promise.all([ fetchUser(t, 'alice') @@ -868,10 +868,10 @@ test.skip('typing indicators', t => { })), fetchUser(t, 'carol') ]) - // FIXME This test (and the corresponding user sub one) occasionally fail if - // isTypingIn is called without this timeout. It would seem that there is a - // race condition *somewhere*. - .then(([x, carol]) => setTimeout(() => carol.isTypingIn(bobsRoom.id), 1000)) + // FIXME This test (and the corresponding room sub one) fail intermittently. + // The corresponding server side test fails too so there might be some kind + // of race condition in the server. Needs more investigation. + .then(([x, carol]) => carol.isTypingIn(bobsRoom.id)) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -916,6 +916,16 @@ test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { t.timeoutAfter(TEST_TIMEOUT) }) +test(`get another user's read cursor before subscribing to a room fails`, t => { + fetchUser(t, 'alice') + .then(alice => { + t.throws(() => alice.readCursor(alicesRoom.id, 'bob'), /subscribe/) + t.end() + }) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + test(`get another user's read cursor after subscribing to a room`, t => { fetchUser(t, 'alice') .then(alice => alice.subscribeToRoom(alicesRoom.id).then(() => alice)) From eedc80253da17e9cfa69675353f2b0fb1bbb4f03 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 1 Mar 2018 11:23:45 +0000 Subject: [PATCH 72/99] a word --- tests/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/main.js b/tests/main.js index 19f00cf..dd3c65c 100644 --- a/tests/main.js +++ b/tests/main.js @@ -868,7 +868,7 @@ test('typing indicators', t => { })), fetchUser(t, 'carol') ]) - // FIXME This test (and the corresponding room sub one) fail intermittently. + // FIXME This test (and the corresponding user sub one) fail intermittently. // The corresponding server side test fails too so there might be some kind // of race condition in the server. Needs more investigation. .then(([x, carol]) => carol.isTypingIn(bobsRoom.id)) From a2f29b1e1c67ea9e9d9631ae86ca39fa79213e0e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 1 Mar 2018 13:37:34 +0000 Subject: [PATCH 73/99] 0.7.0-alpha.1 --- package.json | 2 +- tests/main.js | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/package.json b/package.json index 8ec9110..ad36f1d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha", + "version": "0.7.0-alpha.1", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", diff --git a/tests/main.js b/tests/main.js index dd3c65c..35092c7 100644 --- a/tests/main.js +++ b/tests/main.js @@ -969,7 +969,3 @@ test.skip('non-admin delete room fails gracefully', t => { }) // TODO promote Alice to admin and update and delete rooms successfully - -// TODO files stuff - -// TODO read cursors (perhaps reconsider interface) From 9f34ef8dfb4af4e1c6bcefddd1cb836c8666ae8f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 2 Mar 2018 14:04:02 +0000 Subject: [PATCH 74/99] updateRoom & deleteRoom --- src/current-user.js | 32 +++++++++++++++++++++ tests/main.js | 70 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index d2b9736..29ef006 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -341,6 +341,38 @@ export class CurrentUser { }) } + updateRoom = (roomId, options = {}) => { + typeCheck('roomId', 'number', roomId) + options.name && typeCheck('name', 'string', options.name) + options.private && typeCheck('private', 'boolean', options.private) + return this.apiInstance.request({ + method: 'PUT', + path: `/rooms/${roomId}`, + json: { + name: options.name, + private: options.private + } + }) + .then(() => {}) + .catch(err => { + this.logger.warn('error updating room:', err) + throw err + }) + } + + deleteRoom = roomId => { + typeCheck('roomId', 'number', roomId) + return this.apiInstance.request({ + method: 'DELETE', + path: `/rooms/${roomId}` + }) + .then(() => {}) + .catch(err => { + this.logger.warn('error deleting room:', err) + throw err + }) + } + /* internal */ uploadDataAttachment = (roomId, { file, name }) => { diff --git a/tests/main.js b/tests/main.js index 35092c7..10e0152 100644 --- a/tests/main.js +++ b/tests/main.js @@ -940,32 +940,72 @@ test(`get another user's read cursor after subscribing to a room`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME +// FIXME platform request method should not resolve on failed requests test.skip('non-admin update room fails gracefully', t => { - fetchUser(t, 'alice').then(alice => alice.updateRoom( - alicesRoom.id, - { name: `Alice's updated room` }, - () => t.end(`onSuccess shouldn't be called`), - err => { + fetchUser(t, 'alice') + .then(alice => alice.updateRoom(bobsRoom.id, { + name: `Bob's updated room` + })) + .then(() => t.end(`updateRoom should not resolve`)) + .catch(err => { t.true(toString(err).match(/permission/), 'permission error') t.end() } - )) + ) t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME +// FIXME platform request method should not resolve on failed requests test.skip('non-admin delete room fails gracefully', t => { - fetchUser(t, 'alice').then(alice => alice.updateRoom( - alicesRoom.id, - { name: `Alice's updated room` }, - () => t.end(`onSuccess shouldn't be called`), - err => { + fetchUser(t, 'alice') + .then(alice => alice.deleteRoom(bobsRoom.id)) + .then(() => t.end(`deleteRoom should not resolve`)) + .catch(err => { t.true(toString(err).match(/permission/), 'permission error') t.end() + }) + t.timeoutAfter(TEST_TIMEOUT) +}) + +test('[setup] promote Alice to admin', t => { + server.assignGlobalRoleToUser('alice', 'admin') + .then(() => t.end()) + .catch(endWithErr(t)) +}) + +test(`update room [renames Bob's room]`, t => { + fetchUser(t, 'alice', { + roomUpdated: room => { + t.equal(room.id, bobsRoom.id) + t.equal(room.name, `Bob's updated room`) + t.end() } - )) + }) + .then(alice => alice.updateRoom(bobsRoom.id, { + name: `Bob's updated room` + })) + .then(res => t.equal(res, undefined)) + .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -// TODO promote Alice to admin and update and delete rooms successfully +test(`delete room [deletes Bob's room]`, t => { + let alice + fetchUser(t, 'alice', { + roomDeleted: room => { + t.equal(room.id, bobsRoom.id) + t.false( + any(r => r.id === bobsRoom.id, alice.rooms), + `alice.rooms doesn't contain Bob's room` + ) + t.end() + } + }) + .then(a => { + alice = a + alice.deleteRoom(bobsRoom.id) + }) + .then(res => t.equal(res, undefined)) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) From 4a41fd120b8bd102ba5c2ca777d0bae904ea793f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Mar 2018 12:18:28 +0000 Subject: [PATCH 75/99] 0.7.0-alpha.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad36f1d..8f42ab5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha.1", + "version": "0.7.0-alpha.2", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From 7998301baed98939a7f5fddc9738117430c29c5f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Mar 2018 14:07:58 +0000 Subject: [PATCH 76/99] enable fetch data attachment test --- tests/main.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/main.js b/tests/main.js index 10e0152..8de2a85 100644 --- a/tests/main.js +++ b/tests/main.js @@ -764,18 +764,17 @@ test('receive message with data attachment', t => { t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME pending proper CORS headers being set up on the rich media S3 buckets -test.skip('fetch data attachment', t => { +test('fetch data attachment', t => { fetchUser(t, 'alice') .then(alice => alice.fetchAttachment(dataAttachmentUrl)) .then(attachment => { t.equal(attachment.file.name, 'hello.json') t.equal(attachment.file.bytes, 17) - t.comment(attachment.link) return fetch(attachment.link) }) - .then(json => { - t.equal(json, '{"hello":"world"}') + .then(res => res.json()) + .then(data => { + t.deepEqual(data, { hello: 'world' }) t.end() }) .catch(endWithErr(t)) From e014749b0bc531126405d4de82d5f87110cd2cb5 Mon Sep 17 00:00:00 2001 From: Hamilton Chapman Date: Mon, 5 Mar 2018 14:21:51 +0000 Subject: [PATCH 77/99] Use the presence service for presence-related things --- src/chat-manager.js | 8 +++++++- src/current-user.js | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/chat-manager.js b/src/chat-manager.js index 6062fe0..8b6d8b8 100644 --- a/src/chat-manager.js +++ b/src/chat-manager.js @@ -44,6 +44,11 @@ export class ChatManager { serviceVersion: 'v1', ...instanceOptions }) + this.presenceInstance = new Instance({ + serviceName: 'chatkit_presence', + serviceVersion: 'v1', + ...instanceOptions + }) this.userId = userId } @@ -53,7 +58,8 @@ export class ChatManager { id: this.userId, apiInstance: this.apiInstance, filesInstance: this.filesInstance, - cursorsInstance: this.cursorsInstance + cursorsInstance: this.cursorsInstance, + presenceInstance: this.presenceInstance }) return Promise.all([ currentUser.establishUserSubscription(hooks), diff --git a/src/current-user.js b/src/current-user.js index 29ef006..1cc428f 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -38,12 +38,13 @@ import { MessageSubscription } from './message-subscription' import { Message } from './message' export class CurrentUser { - constructor ({ id, apiInstance, filesInstance, cursorsInstance }) { + constructor ({ id, apiInstance, filesInstance, cursorsInstance, presenceInstance }) { this.id = id this.encodedId = encodeURIComponent(this.id) this.apiInstance = apiInstance this.filesInstance = filesInstance this.cursorsInstance = cursorsInstance + this.presenceInstance = presenceInstance this.logger = apiInstance.logger this.presenceStore = new Store() this.userStore = new UserStore({ @@ -426,7 +427,7 @@ export class CurrentUser { this.presenceSubscription = new PresenceSubscription({ hooks, userId: this.id, - instance: this.apiInstance, + instance: this.presenceInstance, userStore: this.userStore, roomStore: this.roomStore, presenceStore: this.presenceStore, From 0da726e3a9b22b61c5955523a87075891147493d Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 5 Mar 2018 15:26:48 +0000 Subject: [PATCH 78/99] make switching between environments while testing easier --- .gitignore | 6 +++--- package.json | 3 ++- tests/{config.example.js => config/example.js} | 0 tests/main.js | 6 +++++- 4 files changed, 10 insertions(+), 5 deletions(-) rename tests/{config.example.js => config/example.js} (100%) diff --git a/.gitignore b/.gitignore index 205a088..e0b66e5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,6 @@ npm-debug.log yarn-error.log .DS_Store .vscode/ -tests/config.js -tests/config.us1.js -tests/config.deneb.js +tests/config/production.js +tests/config/staging.js +tests/config/development.js diff --git a/package.json b/package.json index 8f42ab5..6f956e6 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "test:raw": "browserify tests/main.js -t babelify | tape-run", "lint:build": "clear && yarn lint && clear && yarn build", "lint:build:test": "yarn lint:build && clear && yarn test", - "lint:build:test:raw": "yarn lint:build && clear && yarn test:raw" + "lint:build:test:raw": "yarn lint:build && clear && yarn test:raw", + "test-context": "f () { sed -i \"s/\\.\\/config\\/[a-z]\\+/\\.\\/config\\/$1/g\" tests/main.js; }; f" }, "babel": { "presets": [ diff --git a/tests/config.example.js b/tests/config/example.js similarity index 100% rename from tests/config.example.js rename to tests/config/example.js diff --git a/tests/main.js b/tests/main.js index 8de2a85..1cfad6e 100644 --- a/tests/main.js +++ b/tests/main.js @@ -19,7 +19,11 @@ import { import ChatkitServer from 'pusher-chatkit-server' import { TokenProvider, ChatManager } from '../dist/web/chatkit.js' -import { INSTANCE_LOCATOR, INSTANCE_KEY, TOKEN_PROVIDER_URL } from './config' +import { + INSTANCE_LOCATOR, + INSTANCE_KEY, + TOKEN_PROVIDER_URL +} from './config/production' let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom, dataAttachmentUrl From f015497dab214ab84567ad9a4bb5c8de857639f5 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 6 Mar 2018 14:29:59 +0000 Subject: [PATCH 79/99] cancel method on subscriptions --- src/current-user.js | 10 ++++++---- src/cursor-subscription.js | 6 +++++- src/message-subscription.js | 6 +++++- src/presence-subscription.js | 6 +++++- src/room-subscription.js | 13 +++++++++++++ src/user-subscription.js | 6 +++++- tests/main.js | 16 ++++++++++++++++ 7 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/room-subscription.js diff --git a/src/current-user.js b/src/current-user.js index 1cc428f..4772c93 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -35,6 +35,7 @@ import { UserSubscription } from './user-subscription' import { PresenceSubscription } from './presence-subscription' import { CursorSubscription } from './cursor-subscription' import { MessageSubscription } from './message-subscription' +import { RoomSubscription } from './room-subscription' import { Message } from './message' export class CurrentUser { @@ -287,9 +288,10 @@ export class CurrentUser { typeCheck('roomId', 'number', roomId) typeCheckObj('hooks', 'function', hooks) messageLimit && typeCheck('messageLimit', 'number', messageLimit) - // TODO what is the desired behaviour if there is already a subscription to - // this room? Close the old one? Throw an error? Merge the hooks? - this.roomSubscriptions[roomId] = { + if (this.roomSubscriptions[roomId]) { + this.roomSubscriptions[roomId].cancel() + } + this.roomSubscriptions[roomId] = new RoomSubscription({ hooks, messageSub: new MessageSubscription({ roomId, @@ -316,7 +318,7 @@ export class CurrentUser { cursorStore: this.cursorStore, instance: this.cursorsInstance }) - } + }) return this.joinRoom(roomId) .then(room => Promise.all([ this.roomSubscriptions[roomId].messageSub.connect(), diff --git a/src/cursor-subscription.js b/src/cursor-subscription.js index c13ae8c..a6da82d 100644 --- a/src/cursor-subscription.js +++ b/src/cursor-subscription.js @@ -13,7 +13,7 @@ export class CursorSubscription { connect () { return new Promise((resolve, reject) => { this.hooks = { ...this.hooks, subscriptionEstablished: resolve } - this.instance.subscribeNonResuming({ + this.sub = this.instance.subscribeNonResuming({ path: this.path, listeners: { onError: reject, @@ -23,6 +23,10 @@ export class CursorSubscription { }) } + cancel () { + this.sub && this.sub.unsubscribe() + } + onEvent = ({ body }) => { switch (body.event_name) { case 'initial_state': diff --git a/src/message-subscription.js b/src/message-subscription.js index 81e0b4e..f7fae7d 100644 --- a/src/message-subscription.js +++ b/src/message-subscription.js @@ -18,7 +18,7 @@ export class MessageSubscription { connect () { return new Promise((resolve, reject) => { - this.instance.subscribeNonResuming({ + this.sub = this.instance.subscribeNonResuming({ path: `/rooms/${this.roomId}?${urlEncode({ message_limit: this.messageLimit })}`, @@ -31,6 +31,10 @@ export class MessageSubscription { }) } + cancel () { + this.sub && this.sub.unsubscribe() + } + onEvent = ({ body }) => { switch (body.event_name) { case 'new_message': diff --git a/src/presence-subscription.js b/src/presence-subscription.js index fe42d67..e788c86 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -25,7 +25,7 @@ export class PresenceSubscription { connect () { return new Promise((resolve, reject) => { this.hooks = { ...this.hooks, subscriptionEstablished: resolve } - this.instance.subscribeNonResuming({ + this.sub = this.instance.subscribeNonResuming({ path: `/users/${encodeURIComponent(this.userId)}/presence`, listeners: { onError: reject, @@ -35,6 +35,10 @@ export class PresenceSubscription { }) } + cancel () { + this.sub && this.sub.unsubscribe() + } + onEvent = ({ body }) => { switch (body.event_name) { case 'initial_state': diff --git a/src/room-subscription.js b/src/room-subscription.js new file mode 100644 index 0000000..ebffeba --- /dev/null +++ b/src/room-subscription.js @@ -0,0 +1,13 @@ +export class RoomSubscription { + constructor ({ hooks, messageSub, cursorSub }) { + this.hooks = hooks + this.messageSub = messageSub + this.cursorSub = cursorSub + } + + cancel () { + this.hooks = {} + this.messageSub.cancel() + this.cursorSub.cancel() + } +} diff --git a/src/user-subscription.js b/src/user-subscription.js index 71b2ea0..b33be6e 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -16,7 +16,7 @@ export class UserSubscription { connect () { return new Promise((resolve, reject) => { this.hooks = { ...this.hooks, subscriptionEstablished: resolve } - this.instance.subscribeNonResuming({ + this.sub = this.instance.subscribeNonResuming({ path: '/users', listeners: { onError: reject, @@ -26,6 +26,10 @@ export class UserSubscription { }) } + cancel () { + this.sub && this.sub.unsubscribe() + } + onEvent = ({ body }) => { switch (body.event_name) { case 'initial_state': diff --git a/tests/main.js b/tests/main.js index 1cfad6e..49b2729 100644 --- a/tests/main.js +++ b/tests/main.js @@ -694,6 +694,22 @@ test('subscribe to room and receive sent messages', t => { t.timeoutAfter(TEST_TIMEOUT) }) +test('unsubscribe from room', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(bobsRoom.id, + { + newMessage: once(m => { + endWithErr(t, 'should not be called after unsubscribe') + }) + }, 0) + .then(() => alice.roomSubscriptions[bobsRoom.id].cancel()) + .then(() => sendMessages(alice, bobsRoom, ['yoooo'])) + .then(() => setTimeout(t.end, 1000)) + ) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + // Attachments test('send message with malformed attachment fails', t => { From 881e2230688ef3e0ab6b43038cd02b982085c0ee Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Mar 2018 11:09:40 +0000 Subject: [PATCH 80/99] 0.7.0-alpha.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f956e6..b61546a 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha.2", + "version": "0.7.0-alpha.3", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From 5bcc0c340a3d78bd597d86a3f9579d037fc1acfe Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Mar 2018 12:20:16 +0000 Subject: [PATCH 81/99] test userWentOffline hook --- tests/main.js | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/tests/main.js b/tests/main.js index 49b2729..d3c6a49 100644 --- a/tests/main.js +++ b/tests/main.js @@ -25,7 +25,8 @@ import { TOKEN_PROVIDER_URL } from './config/production' -let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom, dataAttachmentUrl +let alicesRoom, bobsRoom, carolsRoom, alicesPrivateRoom +let dataAttachmentUrl, bob, carol const TEST_TIMEOUT = 15 * 1000 @@ -319,15 +320,23 @@ test('user came online hook (user sub)', t => { t.end() } }) - .then(() => fetchUser(t, 'bob')) + .then(() => fetchUser(t, 'bob').then(b => { bob = b })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -// We can't easily test for the user going offline, because the presence -// subscription in the above test hangs around until it is garbage collected. -// TODO cancel methods so that we can do this, and because we should have them -// anyway +test('user went offline hook (user sub)', t => { + fetchUser(t, 'alice', { + userWentOffline: user => { + t.equal(user.id, 'bob') + t.equal(user.presence.state, 'offline') + t.end() + } + }) + .then(() => bob.presenceSubscription.cancel()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) test('typing indicators (user sub)', t => { let started @@ -857,16 +866,29 @@ test('user came online hook', t => { userCameOnline: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') + t.equal(user.presence.state, 'online') t.end() }) })) - .then(() => fetchUser(t, 'carol')) + .then(() => fetchUser(t, 'carol').then(c => { carol = c })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) -// We can't easily test for the user going offline, because the presence -// subscription in the above test hangs around until it is garbage collected. +test('user went offline hook', t => { + fetchUser(t, 'alice') + .then(alice => alice.subscribeToRoom(bobsRoom.id, { + userWentOffline: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.equal(user.presence.state, 'offline') + t.end() + }) + })) + .then(() => carol.presenceSubscription.cancel()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) test('typing indicators', t => { let started From 8f08e3b47f9ba1c995149073527193eb18dcb50f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 7 Mar 2018 16:11:20 +0000 Subject: [PATCH 82/99] minimal changes to get existing example working in firefox --- example/index.html | 20 ++++++++ example/main.js | 117 +++++++++++++++++++++++++++++++++++++++++++++ example/style.css | 91 +++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 example/index.html create mode 100644 example/main.js create mode 100644 example/style.css diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..aa3bb2f --- /dev/null +++ b/example/index.html @@ -0,0 +1,20 @@ + + + + Chatkit Example + + + + +
    +
    + +
    + + + +
    +
    SEND
    +
    + + + diff --git a/example/main.js b/example/main.js new file mode 100644 index 0000000..78cc75c --- /dev/null +++ b/example/main.js @@ -0,0 +1,117 @@ +const INSTANCE_LOCATOR = 'YOUR_INSTANCE_LOCATOR' +const TOKEN_PROVIDER_URL = 'YOUR_TOKEN_PROVIDER_URL' +const USER_ID = 'YOUR_USER_ID' + +let currentUser +let room + +const tokenProvider = new Chatkit.TokenProvider({ + url: TOKEN_PROVIDER_URL +}) + +const chatManager = new Chatkit.ChatManager({ + instanceLocator: INSTANCE_LOCATOR, + tokenProvider: tokenProvider, + userId: USER_ID +}) + +chatManager.connect() + .then(cUser => { + currentUser = cUser + const roomToSubscribeTo = currentUser.rooms[0] + + if (roomToSubscribeTo) { + room = roomToSubscribeTo + console.log('Going to subscribe to', roomToSubscribeTo) + currentUser.subscribeToRoom( + roomToSubscribeTo.id, + { + newMessage: message => { + console.log('new message:', message) + const messagesList = document.getElementById('messages') + const messageItem = document.createElement('li') + messageItem.className = 'message' + messagesList.append(messageItem) + const textDiv = document.createElement('div') + textDiv.innerHTML = `${message.sender.name}: ${message.text}` + messageItem.appendChild(textDiv) + + if (message.attachment) { + let attachment + switch (message.attachment.type) { + case 'image': + attachment = document.createElement('img') + break + case 'video': + attachment = document.createElement('video') + attachment.controls = 'controls' + break + case 'audio': + attachment = document.createElement('audio') + attachment.controls = 'controls' + break + default: + break + } + + attachment.className += ' attachment' + attachment.width = '400' + + if (message.attachment.fetchRequired) { + currentUser.fetchAttachment(message.attachment.link) + .then(fetchedAttachment => { + attachment.src = fetchedAttachment.link + messageItem.appendChild(attachment) + }) + .catch(error => { + console.log('Error', error) + }) + } else { + attachment.src = message.attachment.link + messageItem.appendChild(attachment) + } + } + } + } + ) + } else { + console.log('No room to subscribe to') + } + console.log('Successful connection', currentUser) + }) + .catch(err => { + console.log('Error on connection: ', err) + }) + +document.getElementById('send-button').addEventListener('click', ev => { + const fileInput = document.querySelector('input[name=testfile]') + const textInput = document.getElementById('text-input') + + currentUser.sendMessage({ + text: textInput.value, + roomId: room.id, + // attachment: { + // link: 'https://assets.zeit.co/image/upload/front/api/deployment-state.png', + // type: 'image', + // }, + attachment: fileInput.value + ? { + file: fileInput.files[0], + // Split on slashes, remove whitespace + name: fileInput.value.split(/(\\|\/)/g).pop().replace(/\s+/g, ''), + } + : undefined, + }) + .then(messageId => { + console.log('Success!', messageId) + fileInput.value = '' + textInput.value = '' + }) + .catch(error => { + console.log('Error', error) + }) +}) + +document.querySelector('.choose-file').addEventListener('click', () => { + document.querySelector('input[name=testfile]').click() +}) diff --git a/example/style.css b/example/style.css new file mode 100644 index 0000000..e86d743 --- /dev/null +++ b/example/style.css @@ -0,0 +1,91 @@ +body { + font-family: "Helvetica Neue", Helvetica, sans-serif; +} + +#messages { + padding: 0; + margin: 0; + list-style: none; + width: 100%; + text-align: center; + padding-bottom: 50px; +} + +.message { + margin: 8px 0; +} + +.attachment { + margin-top: 4px; +} + +.choose-file { + position: relative; + display: inline-block; + border-left: 1px solid #ebebeb; + border-right: 1px solid #ebebeb; + width: 40px; + height: 40px; + font-size: 30px; + color: #7f7f7f; + background: white; + text-align: center; + float: left; + overflow: hidden; +} + +.choose-file:hover { + cursor: pointer; +} + +.choose-file input[type="file"] { + /* -webkit-appearance: none; */ + /* position: absolute; */ + top: 0; + left: 0; + opacity: 0; + height: 0; + width: 0; +} + +#compose-wrapper { + position: fixed; + bottom: 0; + left: 0; + right: 0; + height: 40px; + border-top: 1px solid #ebebeb; +} + +#text-input { + height: 100%; + width: calc(100% - 70px - 42px); + border: none; + font-size: 28px; + padding: 2px 4px; + float: left; +} + +#text-input:focus { + outline: none; +} + +#send-button { + height: 100%; + width: 70px; + font-weight: 500; + display: inline-block; + text-align: center; + transition: all 0.3s; + padding-top: 10px; + float: left; +} + +#send-button:hover { + cursor: pointer; + color: red; +} + +input[name=testfile] { + display: none; +} From 019458989b5ab18a5917bf2f4206eb610e80bfef Mon Sep 17 00:00:00 2001 From: Hamilton Chapman Date: Wed, 7 Mar 2018 18:15:15 +0000 Subject: [PATCH 83/99] Bump pusher-platform dependency to 0.15.0 and unskip previously skipped tests --- package.json | 2 +- tests/main.js | 14 ++++++++++---- yarn.lock | 6 +++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index b61546a..1e58e5a 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "url": "git+https://github.com/pusher/chatkit-client-js.git" }, "dependencies": { - "pusher-platform": "^0.14.0" + "pusher-platform": "^0.15.0" }, "devDependencies": { "babel-cli": "^6.26.0", diff --git a/tests/main.js b/tests/main.js index d3c6a49..776ffb6 100644 --- a/tests/main.js +++ b/tests/main.js @@ -220,6 +220,14 @@ test('[setup] create Alice', t => { t.timeoutAfter(TEST_TIMEOUT) }) +// this shouldn't be necessary once the server-side bug is fixed such +// that user deletion also leads to relevant user role deletion(s) +test('[setup] assign default role to Alice', t => { + server.assignGlobalRoleToUser('alice', 'default') + .then(() => t.end()) + .catch(endWithErr(t)) +}) + test('connection resolves with current user object', t => { fetchUser(t, 'alice') .then(alice => { @@ -981,8 +989,7 @@ test(`get another user's read cursor after subscribing to a room`, t => { t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME platform request method should not resolve on failed requests -test.skip('non-admin update room fails gracefully', t => { +test('non-admin update room fails gracefully', t => { fetchUser(t, 'alice') .then(alice => alice.updateRoom(bobsRoom.id, { name: `Bob's updated room` @@ -996,8 +1003,7 @@ test.skip('non-admin update room fails gracefully', t => { t.timeoutAfter(TEST_TIMEOUT) }) -// FIXME platform request method should not resolve on failed requests -test.skip('non-admin delete room fails gracefully', t => { +test('non-admin delete room fails gracefully', t => { fetchUser(t, 'alice') .then(alice => alice.deleteRoom(bobsRoom.id)) .then(() => t.end(`deleteRoom should not resolve`)) diff --git a/yarn.lock b/yarn.lock index 34620ab..d9d6b54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3342,9 +3342,9 @@ pusher-platform-node@~0.11.1: jsonwebtoken "^7.4.1" request "^2.81.0" -pusher-platform@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/pusher-platform/-/pusher-platform-0.14.0.tgz#81b410b51c4b1cc31e24d79295af8ef947c3c307" +pusher-platform@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/pusher-platform/-/pusher-platform-0.15.0.tgz#d94c63ceeef5e05e5fc09504f3c7d0971cd218a3" qs@6.5.1, qs@~6.5.1: version "6.5.1" From 2d4a60259e464057a39713146b194d6d5d1f1a07 Mon Sep 17 00:00:00 2001 From: Hamilton Chapman Date: Thu, 8 Mar 2018 14:18:55 +0000 Subject: [PATCH 84/99] Fix CSS in example --- example/index.html | 1 + example/style.css | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/example/index.html b/example/index.html index aa3bb2f..162cc7f 100644 --- a/example/index.html +++ b/example/index.html @@ -1,3 +1,4 @@ + diff --git a/example/style.css b/example/style.css index e86d743..42ed497 100644 --- a/example/style.css +++ b/example/style.css @@ -59,7 +59,10 @@ body { #text-input { height: 100%; - width: calc(100% - 70px - 42px); + /* full width minus send-button width minus choose-file width + (including border * 2 and padding * 2) + */ + width: calc(100% - 70px - 40px - 2px - 8px); border: none; font-size: 28px; padding: 2px 4px; From 89b1d93d190720056a3919e5e8e82acd3a7519fc Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Mar 2018 14:28:16 +0000 Subject: [PATCH 85/99] don't lint example --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 1e58e5a..5e6f5ee 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,8 @@ "plugins": [ "transform-object-rest-spread" ] + }, + "standard": { + "ignore": "example" } } From 8b86e275c1dbff01118ec0e98f401cadc91589dc Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Mar 2018 14:49:03 +0000 Subject: [PATCH 86/99] add some missing timeouts --- tests/main.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/main.js b/tests/main.js index 776ffb6..299ab99 100644 --- a/tests/main.js +++ b/tests/main.js @@ -220,14 +220,6 @@ test('[setup] create Alice', t => { t.timeoutAfter(TEST_TIMEOUT) }) -// this shouldn't be necessary once the server-side bug is fixed such -// that user deletion also leads to relevant user role deletion(s) -test('[setup] assign default role to Alice', t => { - server.assignGlobalRoleToUser('alice', 'default') - .then(() => t.end()) - .catch(endWithErr(t)) -}) - test('connection resolves with current user object', t => { fetchUser(t, 'alice') .then(alice => { @@ -989,6 +981,15 @@ test(`get another user's read cursor after subscribing to a room`, t => { t.timeoutAfter(TEST_TIMEOUT) }) +// this shouldn't be necessary once the server-side bug is fixed such +// that user deletion also leads to relevant user role deletion(s) +test('[setup] assign default role to Alice', t => { + server.assignGlobalRoleToUser('alice', 'default') + .then(() => t.end()) + .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) +}) + test('non-admin update room fails gracefully', t => { fetchUser(t, 'alice') .then(alice => alice.updateRoom(bobsRoom.id, { @@ -1018,6 +1019,7 @@ test('[setup] promote Alice to admin', t => { server.assignGlobalRoleToUser('alice', 'admin') .then(() => t.end()) .catch(endWithErr(t)) + t.timeoutAfter(TEST_TIMEOUT) }) test(`update room [renames Bob's room]`, t => { From 04c569c7c28b89527031a63bfdebfb652da88e5a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Mar 2018 14:49:30 +0000 Subject: [PATCH 87/99] 0.7.0-alpha.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e6f5ee..7b61884 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha.3", + "version": "0.7.0-alpha.4", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From d7db4dcd351591ab8262a6a0050e60b9ebeb1b13 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Mar 2018 10:09:52 +0000 Subject: [PATCH 88/99] only make a single token provider request at a time --- example/index.html | 3 ++- src/token-provider.js | 33 +++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/example/index.html b/example/index.html index 162cc7f..1531c88 100644 --- a/example/index.html +++ b/example/index.html @@ -3,7 +3,8 @@ Chatkit Example - + + diff --git a/src/token-provider.js b/src/token-provider.js index 4129595..84705e7 100644 --- a/src/token-provider.js +++ b/src/token-provider.js @@ -11,22 +11,31 @@ export class TokenProvider { fetchToken = () => !this.cacheIsStale() ? Promise.resolve(this.cachedToken) - : this.fetchFreshToken().then(({ token, expiresIn }) => { + : (this.req || this.fetchFreshToken()).then(({ token, expiresIn }) => { this.cache(token, expiresIn) return token }) - fetchFreshToken = () => sendRawRequest({ - method: 'POST', - url: appendQueryParam('user_id', this.userId, this.url), - body: urlEncode({ grant_type: 'client_credentials' }), - headers: { - 'content-type': 'application/x-www-form-urlencoded' - } - }).then(res => { - const { access_token: token, expires_in: expiresIn } = JSON.parse(res) - return { token, expiresIn } - }) + fetchFreshToken = () => { + this.req = sendRawRequest({ + method: 'POST', + url: appendQueryParam('user_id', this.userId, this.url), + body: urlEncode({ grant_type: 'client_credentials' }), + headers: { + 'content-type': 'application/x-www-form-urlencoded' + } + }) + .then(res => { + const { access_token: token, expires_in: expiresIn } = JSON.parse(res) + this.req = undefined + return { token, expiresIn } + }) + .catch(err => { + this.req = undefined + throw err + }) + return this.req + } cacheIsStale = () => !this.cachedToken || unixSeconds() > this.cacheExpiresAt From 775f14425eeec5557e34fe2c740d6674c213561c Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Mar 2018 10:17:07 +0000 Subject: [PATCH 89/99] 0.7.0-alpha.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b61884..6b5c8c0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha.4", + "version": "0.7.0-alpha.5", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From 42e92d0102ad769701ee3080bebcac3df7dba51e Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 9 Mar 2018 16:23:34 +0000 Subject: [PATCH 90/99] queryPrams and headers options for TokenProvider --- src/token-provider.js | 17 ++++++++++++----- src/user-store.js | 7 +++++-- src/utils.js | 6 ++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/token-provider.js b/src/token-provider.js index 84705e7..df256e4 100644 --- a/src/token-provider.js +++ b/src/token-provider.js @@ -1,12 +1,15 @@ import { sendRawRequest } from 'pusher-platform' -import { appendQueryParam, typeCheck, unixSeconds, urlEncode } from './utils' +import { appendQueryParams, typeCheck, unixSeconds, urlEncode } from './utils' export class TokenProvider { - // TODO authContext - constructor ({ url } = {}) { + constructor ({ url, queryParams, headers } = {}) { typeCheck('url', 'string', url) + queryParams && typeCheck('queryParams', 'object', queryParams) + headers && typeCheck('headers', 'object', headers) this.url = url + this.queryParams = queryParams + this.headers = headers } fetchToken = () => !this.cacheIsStale() @@ -19,10 +22,14 @@ export class TokenProvider { fetchFreshToken = () => { this.req = sendRawRequest({ method: 'POST', - url: appendQueryParam('user_id', this.userId, this.url), + url: appendQueryParams( + { user_id: this.userId, ...this.queryParams }, + this.url + ), body: urlEncode({ grant_type: 'client_credentials' }), headers: { - 'content-type': 'application/x-www-form-urlencoded' + 'content-type': 'application/x-www-form-urlencoded', + ...this.headers } }) .then(res => { diff --git a/src/user-store.js b/src/user-store.js index f9dc7c9..679ff76 100644 --- a/src/user-store.js +++ b/src/user-store.js @@ -9,7 +9,7 @@ import { values } from 'ramda' -import { appendQueryParam } from './utils' +import { appendQueryParams } from './utils' import { Store } from './store' import { parseBasicUser } from './parsers' import { User } from './user' @@ -63,7 +63,10 @@ export class UserStore { return this.instance .request({ method: 'GET', - path: appendQueryParam('user_ids', join(',', missing), '/users_by_ids') + path: appendQueryParams( + { user_ids: join(',', missing) }, + '/users_by_ids' + ) }) .then(pipe( JSON.parse, diff --git a/src/utils.js b/src/utils.js index 330f3c6..4835f44 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,7 +10,6 @@ import { toPairs } from 'ramda' -// urlEncode :: Object -> String export const urlEncode = pipe( filter(x => x !== undefined), toPairs, @@ -18,10 +17,9 @@ export const urlEncode = pipe( join('&') ) -// appendQueryParam :: String -> String -> String -> String -export const appendQueryParam = (key, value, url) => { +export const appendQueryParams = (queryParams, url) => { const separator = contains('?', url) ? '&' : '?' - return url + separator + urlEncode({ [key]: value }) + return url + separator + urlEncode(queryParams) } export const extractQueryParams = url => From bc2f2ab28f6acd3c92ca723d468880f78a070924 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Mar 2018 10:38:08 +0000 Subject: [PATCH 91/99] 0.7.0-alpha.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b5c8c0..81a068c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", "types": "dist/web/declarations/index.d.ts", - "version": "0.7.0-alpha.5", + "version": "0.7.0-alpha.6", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From 8d1d3d1f5fc6f977672265275530e066d762cb19 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Mar 2018 12:30:52 +0000 Subject: [PATCH 92/99] react native build --- package.json | 11 ++++++----- rollup/react-native.js | 21 ++++++++++++++++++++ rollup/shared.js | 45 ++++++++++++++++++++++++++++++++++++++++++ rollup/web.js | 45 ++++++------------------------------------ yarn.lock | 25 ++++++++++++++++++++++- 5 files changed, 102 insertions(+), 45 deletions(-) create mode 100644 rollup/react-native.js create mode 100644 rollup/shared.js diff --git a/package.json b/package.json index 81a068c..b4650c5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "pusher-chatkit-client", "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", - "types": "dist/web/declarations/index.d.ts", "version": "0.7.0-alpha.6", "author": "Pusher", "license": "MIT", @@ -15,7 +14,8 @@ "url": "git+https://github.com/pusher/chatkit-client-js.git" }, "dependencies": { - "pusher-platform": "^0.15.0" + "pusher-platform": "^0.15.0", + "ramda": "^0.25.0" }, "devDependencies": { "babel-cli": "^6.26.0", @@ -29,11 +29,12 @@ "browserify": "^15.2.0", "faucet": "^0.0.1", "pusher-chatkit-server": "^0.9.1", - "ramda": "^0.25.0", "rollup": "^0.55.3", + "rollup-plugin-alias": "^1.4.0", "rollup-plugin-babel": "^3.0.3", "rollup-plugin-commonjs": "^8.3.0", "rollup-plugin-node-resolve": "^3.0.2", + "rollup-plugin-uglify": "^3.0.0", "snazzy": "^7.0.0", "standard": "^10.0.3", "tape": "^4.8.0", @@ -41,9 +42,9 @@ }, "scripts": { "lint": "standard --parser babel-eslint --verbose | snazzy", - "build": "yarn build:all", - "build:all": "yarn build:web", + "build": "yarn build:web && yarn build:react-native", "build:web": "rollup -c rollup/web.js", + "build:react-native": "rollup -c rollup/react-native.js", "test": "yarn test:raw | faucet", "test:raw": "browserify tests/main.js -t babelify | tape-run", "lint:build": "clear && yarn lint && clear && yarn build", diff --git a/rollup/react-native.js b/rollup/react-native.js new file mode 100644 index 0000000..a07ab8b --- /dev/null +++ b/rollup/react-native.js @@ -0,0 +1,21 @@ +import { merge } from 'ramda' +import alias from 'rollup-plugin-alias' +import path from 'path' + +import shared from './shared' + +export default merge(shared, { + output: { + file: 'dist/react-native/chatkit.js', + format: 'cjs', + name: 'Chatkit' + }, + plugins: [ + alias({ + 'pusher-platform': path.resolve( + './node_modules/pusher-platform/react-native.js' + ) + }), + ...shared.plugins + ] +}) diff --git a/rollup/shared.js b/rollup/shared.js new file mode 100644 index 0000000..ffa1490 --- /dev/null +++ b/rollup/shared.js @@ -0,0 +1,45 @@ +import babel from 'rollup-plugin-babel' +import commonjs from 'rollup-plugin-commonjs' +import resolve from 'rollup-plugin-node-resolve' +import uglify from 'rollup-plugin-uglify' + +const pusherPlatformExports = [ + 'BaseClient', + 'HOST_BASE', + 'Instance', + 'sendRawRequest' +] + +export default { + input: 'src/main.js', + plugins: [ + babel({ + babelrc: false, + presets: [ + [ + 'env', + { + modules: false + } + ] + ], + plugins: [ + 'external-helpers', + 'transform-class-properties', + 'transform-object-rest-spread' + ], + exclude: [ + 'node_modules/**' + ] + }), + resolve(), + commonjs({ + namedExports: { + 'node_modules/pusher-platform/dist/web/pusher-platform.js': + pusherPlatformExports, + 'node_modules/pusher-platform/react-native.js': pusherPlatformExports + } + }), + uglify() + ] +} diff --git a/rollup/web.js b/rollup/web.js index dea7fa1..e7789a3 100644 --- a/rollup/web.js +++ b/rollup/web.js @@ -1,44 +1,11 @@ -import babel from 'rollup-plugin-babel' -import commonjs from 'rollup-plugin-commonjs' -import resolve from 'rollup-plugin-node-resolve' +import { merge } from 'ramda' -export default { - input: 'src/main.js', +import shared from './shared' + +export default merge(shared, { output: { file: 'dist/web/chatkit.js', format: 'umd', name: 'Chatkit' - }, - plugins: [ - babel({ - babelrc: false, - presets: [ - [ - 'env', - { - modules: false - } - ] - ], - plugins: [ - 'external-helpers', - 'transform-class-properties', - 'transform-object-rest-spread' - ], - exclude: [ - 'node_modules/**' - ] - }), - resolve(), - commonjs({ - namedExports: { - 'node_modules/pusher-platform/dist/web/pusher-platform.js': [ - 'BaseClient', - 'HOST_BASE', - 'Instance', - 'sendRawRequest' - ] - } - }) - ] -} + } +}) diff --git a/yarn.lock b/yarn.lock index d9d6b54..70ceef8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1126,7 +1126,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@^2.11.0: +commander@^2.11.0, commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -3680,6 +3680,12 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" +rollup-plugin-alias@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-alias/-/rollup-plugin-alias-1.4.0.tgz#120cba7c46621c03138f0ca6fd5dd2ade9872db9" + dependencies: + slash "^1.0.0" + rollup-plugin-babel@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-3.0.3.tgz#63adedc863130327512a4a9006efc2241c5b7c15" @@ -3704,6 +3710,12 @@ rollup-plugin-node-resolve@^3.0.2: is-module "^1.0.0" resolve "^1.1.6" +rollup-plugin-uglify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-uglify/-/rollup-plugin-uglify-3.0.0.tgz#a34eca24617709c6bf1778e9653baafa06099b86" + dependencies: + uglify-es "^3.3.7" + rollup-pluginutils@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" @@ -3850,6 +3862,10 @@ source-map@^0.5.6, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -4298,6 +4314,13 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +uglify-es@^3.3.7: + version "3.3.9" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" From 2bad618fd8bf3816b1b64569b1edd31f3ab42377 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 12 Mar 2018 17:19:44 +0000 Subject: [PATCH 93/99] inline test babel config --- package.json | 12 ++---------- rollup/shared.js | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index b4650c5..d51341a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "pusher-chatkit-client", "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", - "version": "0.7.0-alpha.6", + "version": "0.7.0-alpha.7.react-native.1", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", @@ -46,20 +46,12 @@ "build:web": "rollup -c rollup/web.js", "build:react-native": "rollup -c rollup/react-native.js", "test": "yarn test:raw | faucet", - "test:raw": "browserify tests/main.js -t babelify | tape-run", + "test:raw": "browserify tests/main.js -t [ babelify --presets env --plugins transform-object-rest-spread ] | tape-run", "lint:build": "clear && yarn lint && clear && yarn build", "lint:build:test": "yarn lint:build && clear && yarn test", "lint:build:test:raw": "yarn lint:build && clear && yarn test:raw", "test-context": "f () { sed -i \"s/\\.\\/config\\/[a-z]\\+/\\.\\/config\\/$1/g\" tests/main.js; }; f" }, - "babel": { - "presets": [ - "env" - ], - "plugins": [ - "transform-object-rest-spread" - ] - }, "standard": { "ignore": "example" } diff --git a/rollup/shared.js b/rollup/shared.js index ffa1490..f527928 100644 --- a/rollup/shared.js +++ b/rollup/shared.js @@ -14,7 +14,6 @@ export default { input: 'src/main.js', plugins: [ babel({ - babelrc: false, presets: [ [ 'env', From 2787635c67c2382026b43c205bcc1b81ee0277e3 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 10:05:37 +0000 Subject: [PATCH 94/99] addUser -> addUserToRoom; removeUser -> removeUserFromRoom --- src/current-user.js | 4 ++-- tests/main.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index 4772c93..d66b17e 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -190,7 +190,7 @@ export class CurrentUser { }) } - addUser = (userId, roomId) => { + addUserToRoom = (userId, roomId) => { typeCheck('userId', 'string', userId) typeCheck('roomId', 'number', roomId) return this.apiInstance @@ -208,7 +208,7 @@ export class CurrentUser { }) } - removeUser = (userId, roomId) => { + removeUserFromRoom = (userId, roomId) => { typeCheck('userId', 'string', userId) typeCheck('roomId', 'number', roomId) return this.apiInstance diff --git a/tests/main.js b/tests/main.js index 299ab99..f8c213e 100644 --- a/tests/main.js +++ b/tests/main.js @@ -588,7 +588,7 @@ test(`leave room [Bob leaves Alice's room]`, t => { test('add user [Alice adds Bob to her room]', t => { fetchUser(t, 'alice') - .then(alice => alice.addUser('bob', alicesRoom.id) + .then(alice => alice.addUserToRoom('bob', alicesRoom.id) .then(() => { const room = find(r => r.id === alicesRoom.id, alice.rooms) t.deepEqual(room.userIds.sort(), ['alice', 'bob']) @@ -601,7 +601,7 @@ test('add user [Alice adds Bob to her room]', t => { test('remove user [Alice removes Bob from her room]', t => { fetchUser(t, 'alice') - .then(alice => alice.removeUser('bob', alicesRoom.id) + .then(alice => alice.removeUserFromRoom('bob', alicesRoom.id) .then(() => { const room = find(r => r.id === alicesRoom.id, alice.rooms) t.deepEqual(room.userIds.sort(), ['alice']) From c9a696f094dd89395705a615a8f89506298bd076 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 11:01:42 +0000 Subject: [PATCH 95/99] functions all recive a single object parameter --- src/current-user.js | 43 +++++----- tests/main.js | 187 +++++++++++++++++++++++++++----------------- 2 files changed, 141 insertions(+), 89 deletions(-) diff --git a/src/current-user.js b/src/current-user.js index d66b17e..774cd6a 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -39,7 +39,13 @@ import { RoomSubscription } from './room-subscription' import { Message } from './message' export class CurrentUser { - constructor ({ id, apiInstance, filesInstance, cursorsInstance, presenceInstance }) { + constructor ({ + apiInstance, + cursorsInstance, + filesInstance, + id, + presenceInstance + }) { this.id = id this.encodedId = encodeURIComponent(this.id) this.apiInstance = apiInstance @@ -82,7 +88,7 @@ export class CurrentUser { return values(this.userStore.snapshot()) } - setReadCursor = (roomId, position) => { + setReadCursor = ({ roomId, position } = {}) => { typeCheck('roomId', 'number', roomId) typeCheck('position', 'number', position) return this.cursorsInstance @@ -98,7 +104,7 @@ export class CurrentUser { }) } - readCursor = (roomId, userId = this.id) => { + readCursor = ({ roomId, userId = this.id } = {}) => { typeCheck('roomId', 'number', roomId) typeCheck('userId', 'string', userId) if (userId !== this.id && !has(roomId, this.roomSubscriptions)) { @@ -111,7 +117,7 @@ export class CurrentUser { return this.cursorStore.getSync(userId, roomId) } - isTypingIn = roomId => { + isTypingIn = ({ roomId } = {}) => { typeCheck('roomId', 'number', roomId) return this.typingIndicators.sendThrottledRequest(roomId) } @@ -156,7 +162,7 @@ export class CurrentUser { return this.getJoinableRooms().then(concat(this.rooms)) } - joinRoom = roomId => { + joinRoom = ({ roomId } = {}) => { typeCheck('roomId', 'number', roomId) if (this.isMemberOf(roomId)) { return this.roomStore.get(roomId) @@ -176,7 +182,7 @@ export class CurrentUser { }) } - leaveRoom = roomId => { + leaveRoom = ({ roomId } = {}) => { typeCheck('roomId', 'number', roomId) return this.apiInstance .request({ @@ -190,7 +196,7 @@ export class CurrentUser { }) } - addUserToRoom = (userId, roomId) => { + addUserToRoom = ({ userId, roomId } = {}) => { typeCheck('userId', 'string', userId) typeCheck('roomId', 'number', roomId) return this.apiInstance @@ -208,7 +214,7 @@ export class CurrentUser { }) } - removeUserFromRoom = (userId, roomId) => { + removeUserFromRoom = ({ userId, roomId } = {}) => { typeCheck('userId', 'string', userId) typeCheck('roomId', 'number', roomId) return this.apiInstance @@ -229,7 +235,7 @@ export class CurrentUser { }) } - sendMessage = ({ text, roomId, attachment }) => { + sendMessage = ({ text, roomId, attachment } = {}) => { typeCheck('text', 'string', text) typeCheck('roomId', 'number', roomId) return new Promise((resolve, reject) => { @@ -255,7 +261,7 @@ export class CurrentUser { }) } - fetchMessages = (roomId, { initialId, limit, direction } = {}) => { + fetchMessages = ({ roomId, initialId, limit, direction } = {}) => { typeCheck('roomId', 'number', roomId) initialId && typeCheck('initialId', 'number', initialId) limit && typeCheck('limit', 'number', limit) @@ -284,7 +290,7 @@ export class CurrentUser { }) } - subscribeToRoom = (roomId, hooks = {}, messageLimit) => { + subscribeToRoom = ({ roomId, hooks = {}, messageLimit } = {}) => { typeCheck('roomId', 'number', roomId) typeCheckObj('hooks', 'function', hooks) messageLimit && typeCheck('messageLimit', 'number', messageLimit) @@ -319,7 +325,7 @@ export class CurrentUser { instance: this.cursorsInstance }) }) - return this.joinRoom(roomId) + return this.joinRoom({ roomId }) .then(room => Promise.all([ this.roomSubscriptions[roomId].messageSub.connect(), this.roomSubscriptions[roomId].cursorSub.connect() @@ -330,7 +336,7 @@ export class CurrentUser { }) } - fetchAttachment = url => { + fetchAttachment = ({ url } = {}) => { return this.filesInstance.tokenProvider.fetchToken() .then(token => sendRawRequest({ method: 'GET', @@ -344,16 +350,15 @@ export class CurrentUser { }) } - updateRoom = (roomId, options = {}) => { + updateRoom = ({ roomId, name, ...rest } = {}) => { typeCheck('roomId', 'number', roomId) - options.name && typeCheck('name', 'string', options.name) - options.private && typeCheck('private', 'boolean', options.private) + name && typeCheck('name', 'string', name) return this.apiInstance.request({ method: 'PUT', path: `/rooms/${roomId}`, json: { - name: options.name, - private: options.private + name: name, + private: !!rest.private // private is a reserved word in strict mode! } }) .then(() => {}) @@ -363,7 +368,7 @@ export class CurrentUser { }) } - deleteRoom = roomId => { + deleteRoom = ({ roomId } = {}) => { typeCheck('roomId', 'number', roomId) return this.apiInstance.request({ method: 'DELETE', diff --git a/tests/main.js b/tests/main.js index f8c213e..c3ddea0 100644 --- a/tests/main.js +++ b/tests/main.js @@ -246,7 +246,7 @@ test('connection resolves with current user object', t => { test('own read cursor undefined if not set', t => { fetchUser(t, 'alice') .then(alice => { - t.equal(alice.readCursor(alicesRoom.id), undefined) + t.equal(alice.readCursor({ roomId: alicesRoom.id }), undefined) t.end() }) .catch(endWithErr(t)) @@ -263,7 +263,7 @@ test('new read cursor hook [Alice sets her read cursor in her room]', t => { } })]) .then(([mobileAlice, browserAlice]) => - mobileAlice.setReadCursor(alicesRoom.id, 42) + mobileAlice.setReadCursor({ roomId: alicesRoom.id, position: 42 }) ) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) @@ -272,7 +272,7 @@ test('new read cursor hook [Alice sets her read cursor in her room]', t => { test('get own read cursor', t => { fetchUser(t, 'alice') .then(alice => { - const cursor = alice.readCursor(alicesRoom.id) + const cursor = alice.readCursor({ roomId: alicesRoom.id }) t.equal(cursor.position, 42) t.equal(cursor.user.name, 'Alice') t.equal(cursor.room.name, `Alice's room`) @@ -359,7 +359,7 @@ test('typing indicators (user sub)', t => { // FIXME This test (and the corresponding room sub one) fail intermittently. // The corresponding server side test fails too so there might be some kind // of race condition in the server. Needs more investigation. - .then(([alice, bob]) => bob.isTypingIn(bobsRoom.id)) + .then(([alice, bob]) => bob.isTypingIn({ roomId: bobsRoom.id })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -550,7 +550,7 @@ test('get all rooms', t => { test(`join room [Bob joins Alice's room]`, t => { fetchUser(t, 'bob') - .then(bob => bob.joinRoom(alicesRoom.id) + .then(bob => bob.joinRoom({ roomId: alicesRoom.id }) .then(room => { t.equal(room.id, alicesRoom.id) t.equal(room.createdByUserId, 'alice') @@ -573,7 +573,7 @@ test(`leave room [Bob leaves Alice's room]`, t => { any(r => r.id === alicesRoom.id, bob.rooms), `should include Bob's room` ) - bob.leaveRoom(alicesRoom.id) + bob.leaveRoom({ roomId: alicesRoom.id }) .then(() => { t.false( any(r => r.id === alicesRoom.id, bob.rooms), @@ -588,7 +588,10 @@ test(`leave room [Bob leaves Alice's room]`, t => { test('add user [Alice adds Bob to her room]', t => { fetchUser(t, 'alice') - .then(alice => alice.addUserToRoom('bob', alicesRoom.id) + .then(alice => alice.addUserToRoom({ + userId: 'bob', + roomId: alicesRoom.id + }) .then(() => { const room = find(r => r.id === alicesRoom.id, alice.rooms) t.deepEqual(room.userIds.sort(), ['alice', 'bob']) @@ -601,7 +604,10 @@ test('add user [Alice adds Bob to her room]', t => { test('remove user [Alice removes Bob from her room]', t => { fetchUser(t, 'alice') - .then(alice => alice.removeUserFromRoom('bob', alicesRoom.id) + .then(alice => alice.removeUserFromRoom({ + userId: 'bob', + roomId: alicesRoom.id + }) .then(() => { const room = find(r => r.id === alicesRoom.id, alice.rooms) t.deepEqual(room.userIds.sort(), ['alice']) @@ -624,7 +630,7 @@ test(`send messages [sends four messages to Bob's room]`, t => { test('fetch messages', t => { fetchUser(t, 'alice') - .then(alice => alice.fetchMessages(bobsRoom.id)) + .then(alice => alice.fetchMessages({ roomId: bobsRoom.id })) .then(messages => { t.deepEqual(messages.map(m => m.text), ['hello', 'hey', 'hi', 'ho']) t.equal(messages[0].sender.id, 'alice') @@ -639,12 +645,15 @@ test('fetch messages', t => { test('fetch messages with pagination', t => { fetchUser(t, 'alice') - .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 2 }) + .then(alice => alice.fetchMessages({ roomId: bobsRoom.id, limit: 2 }) .then(messages => { t.deepEqual(messages.map(m => m.text), ['hi', 'ho']) return messages[0].id }) - .then(initialId => alice.fetchMessages(bobsRoom.id, { initialId })) + .then(initialId => alice.fetchMessages({ + roomId: bobsRoom.id, + initialId + })) .then(messages => { t.deepEqual(messages.map(m => m.text), ['hello', 'hey']) t.end() @@ -656,9 +665,9 @@ test('fetch messages with pagination', t => { test('subscribe to room and fetch initial messages', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom( - bobsRoom.id, - { + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { newMessage: concatBatch(4, messages => { t.deepEqual(map(m => m.text, messages), ['hello', 'hey', 'hi', 'ho']) t.equal(messages[0].sender.name, 'Alice') @@ -666,38 +675,41 @@ test('subscribe to room and fetch initial messages', t => { t.end() }) } - )) + })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) test('subscribe to room and fetch last two message only', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom( - bobsRoom.id, - { + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { newMessage: concatBatch(2, messages => { t.deepEqual(map(m => m.text, messages), ['hi', 'ho']) t.end() }) }, - 2 - )) + messageLimit: 2 + })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) test('subscribe to room and receive sent messages', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, - { + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { newMessage: concatBatch(3, messages => { t.deepEqual(map(m => m.text, messages), ['yo', 'yoo', 'yooo']) t.equal(messages[0].sender.name, 'Alice') t.equal(messages[0].room.name, `Bob's new room`) t.end() }) - }, 0).then(() => sendMessages(alice, bobsRoom, ['yo', 'yoo', 'yooo'])) + }, + messageLimit: 0 + }).then(() => sendMessages(alice, bobsRoom, ['yo', 'yoo', 'yooo'])) ) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) @@ -705,12 +717,15 @@ test('subscribe to room and receive sent messages', t => { test('unsubscribe from room', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, - { + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { newMessage: once(m => { endWithErr(t, 'should not be called after unsubscribe') }) - }, 0) + }, + messageLimit: 0 + }) .then(() => alice.roomSubscriptions[bobsRoom.id].cancel()) .then(() => sendMessages(alice, bobsRoom, ['yoooo'])) .then(() => setTimeout(t.end, 1000)) @@ -749,7 +764,7 @@ test(`send message with link attachment [sends a message to Bob's room]`, t => { test('receive message with link attachment', t => { fetchUser(t, 'alice') - .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 1 })) + .then(alice => alice.fetchMessages({ roomId: bobsRoom.id, limit: 1 })) .then(([message]) => { t.equal(message.text, 'see attached link') t.deepEqual(message.attachment, { @@ -781,7 +796,7 @@ test(`send message with data attachment [sends a message to Bob's room]`, t => { test('receive message with data attachment', t => { fetchUser(t, 'alice') - .then(alice => alice.fetchMessages(bobsRoom.id, { limit: 1 })) + .then(alice => alice.fetchMessages({ roomId: bobsRoom.id, limit: 1 })) .then(([message]) => { t.equal(message.text, 'see attached json') t.equal(message.attachment.type, 'file') @@ -795,7 +810,7 @@ test('receive message with data attachment', t => { test('fetch data attachment', t => { fetchUser(t, 'alice') - .then(alice => alice.fetchAttachment(dataAttachmentUrl)) + .then(alice => alice.fetchAttachment({ url: dataAttachmentUrl })) .then(attachment => { t.equal(attachment.file.name, 'hello.json') t.equal(attachment.file.bytes, 17) @@ -823,7 +838,7 @@ test('[setup] create Carol', t => { test('subscribe to room implicitly joins', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(carolsRoom.id) + .then(alice => alice.subscribeToRoom({ roomId: carolsRoom.id }) .then(room => { t.equal(room.id, carolsRoom.id) t.true(room.name, `Carol's room`) @@ -841,12 +856,15 @@ test('subscribe to room implicitly joins', t => { test(`user joined hook [Carol joins Bob's room]`, t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, { - userJoined: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.end() - }) + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { + userJoined: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.end() + }) + } })) .then(() => server.apiRequest({ method: 'PUT', @@ -862,13 +880,16 @@ test(`user joined hook [Carol joins Bob's room]`, t => { // subscription (since then she will already be online) test('user came online hook', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, { - userCameOnline: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.equal(user.presence.state, 'online') - t.end() - }) + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { + userCameOnline: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.equal(user.presence.state, 'online') + t.end() + }) + } })) .then(() => fetchUser(t, 'carol').then(c => { carol = c })) .catch(endWithErr(t)) @@ -877,13 +898,16 @@ test('user came online hook', t => { test('user went offline hook', t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, { - userWentOffline: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.equal(user.presence.state, 'offline') - t.end() - }) + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { + userWentOffline: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.equal(user.presence.state, 'offline') + t.end() + }) + } })) .then(() => carol.presenceSubscription.cancel()) .catch(endWithErr(t)) @@ -894,7 +918,9 @@ test('typing indicators', t => { let started Promise.all([ fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, { + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { userStartedTyping: once(user => { started = Date.now() t.equal(user.id, 'carol') @@ -906,25 +932,29 @@ test('typing indicators', t => { t.true(Date.now() - started > 1000, 'fired more than 1s after start') t.end() }) - })), + } + })), fetchUser(t, 'carol') ]) // FIXME This test (and the corresponding user sub one) fail intermittently. // The corresponding server side test fails too so there might be some kind // of race condition in the server. Needs more investigation. - .then(([x, carol]) => carol.isTypingIn(bobsRoom.id)) + .then(([x, carol]) => carol.isTypingIn({ roomId: bobsRoom.id })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) test(`user left hook [removes Carol from Bob's room]`, t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(bobsRoom.id, { - userLeft: once(user => { - t.equal(user.id, 'carol') - t.equal(user.name, 'Carol') - t.end() - }) + .then(alice => alice.subscribeToRoom({ + roomId: bobsRoom.id, + hooks: { + userLeft: once(user => { + t.equal(user.id, 'carol') + t.equal(user.name, 'Carol') + t.end() + }) + } })) .then(() => server.apiRequest({ method: 'PUT', @@ -941,18 +971,24 @@ test(`user left hook [removes Carol from Bob's room]`, t => { test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { Promise.all([ fetchUser(t, 'bob') - .then(bob => bob.joinRoom(alicesRoom.id).then(() => bob)), + .then(bob => bob.joinRoom({ roomId: alicesRoom.id }).then(() => bob)), fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(alicesRoom.id, { + .then(alice => alice.subscribeToRoom({ + roomId: alicesRoom.id, + hooks: { newReadCursor: cursor => { t.equal(cursor.position, 128) t.equal(cursor.user.name, 'Bob') t.equal(cursor.room.name, `Alice's new room`) t.end() } - })) + } + })) ]) - .then(([bob]) => bob.setReadCursor(alicesRoom.id, 128)) + .then(([bob]) => bob.setReadCursor({ + roomId: alicesRoom.id, + position: 128 + })) .catch(endWithErr(t)) t.timeoutAfter(TEST_TIMEOUT) }) @@ -960,7 +996,10 @@ test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { test(`get another user's read cursor before subscribing to a room fails`, t => { fetchUser(t, 'alice') .then(alice => { - t.throws(() => alice.readCursor(alicesRoom.id, 'bob'), /subscribe/) + t.throws(() => alice.readCursor({ + roomId: alicesRoom.id, + userId: 'bob' + }), /subscribe/) t.end() }) .catch(endWithErr(t)) @@ -969,9 +1008,15 @@ test(`get another user's read cursor before subscribing to a room fails`, t => { test(`get another user's read cursor after subscribing to a room`, t => { fetchUser(t, 'alice') - .then(alice => alice.subscribeToRoom(alicesRoom.id).then(() => alice)) + .then(alice => alice + .subscribeToRoom({ roomId: alicesRoom.id }) + .then(() => alice) + ) .then(alice => { - const cursor = alice.readCursor(alicesRoom.id, 'bob') + const cursor = alice.readCursor({ + roomId: alicesRoom.id, + userId: 'bob' + }) t.equal(cursor.position, 128) t.equal(cursor.user.name, 'Bob') t.equal(cursor.room.name, `Alice's new room`) @@ -992,7 +1037,8 @@ test('[setup] assign default role to Alice', t => { test('non-admin update room fails gracefully', t => { fetchUser(t, 'alice') - .then(alice => alice.updateRoom(bobsRoom.id, { + .then(alice => alice.updateRoom({ + roomId: bobsRoom.id, name: `Bob's updated room` })) .then(() => t.end(`updateRoom should not resolve`)) @@ -1006,7 +1052,7 @@ test('non-admin update room fails gracefully', t => { test('non-admin delete room fails gracefully', t => { fetchUser(t, 'alice') - .then(alice => alice.deleteRoom(bobsRoom.id)) + .then(alice => alice.deleteRoom({ roomId: bobsRoom.id })) .then(() => t.end(`deleteRoom should not resolve`)) .catch(err => { t.true(toString(err).match(/permission/), 'permission error') @@ -1030,7 +1076,8 @@ test(`update room [renames Bob's room]`, t => { t.end() } }) - .then(alice => alice.updateRoom(bobsRoom.id, { + .then(alice => alice.updateRoom({ + roomId: bobsRoom.id, name: `Bob's updated room` })) .then(res => t.equal(res, undefined)) @@ -1052,7 +1099,7 @@ test(`delete room [deletes Bob's room]`, t => { }) .then(a => { alice = a - alice.deleteRoom(bobsRoom.id) + alice.deleteRoom({ roomId: bobsRoom.id }) }) .then(res => t.equal(res, undefined)) .catch(endWithErr(t)) From 83f1545e922f8d9fcb918f89a39b66cc3acb5248 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 11:17:29 +0000 Subject: [PATCH 96/99] append 'on' to all hooks --- example/main.js | 2 +- src/current-user.js | 8 +++--- src/message-subscription.js | 4 +-- src/presence-subscription.js | 4 +-- src/typing-indicators.js | 16 ++++++------ src/user-subscription.js | 32 ++++++++++++------------ tests/main.js | 48 ++++++++++++++++++------------------ 7 files changed, 57 insertions(+), 57 deletions(-) diff --git a/example/main.js b/example/main.js index 78cc75c..fabebe8 100644 --- a/example/main.js +++ b/example/main.js @@ -26,7 +26,7 @@ chatManager.connect() currentUser.subscribeToRoom( roomToSubscribeTo.id, { - newMessage: message => { + onNewMessage: message => { console.log('new message:', message) const messagesList = document.getElementById('messages') const messageItem = document.createElement('li') diff --git a/src/current-user.js b/src/current-user.js index 774cd6a..2f1e7e2 100644 --- a/src/current-user.js +++ b/src/current-user.js @@ -313,10 +313,10 @@ export class CurrentUser { hooks: { newCursor: cursor => { if ( - hooks.newReadCursor && cursor.type === 0 && + hooks.onNewReadCursor && cursor.type === 0 && cursor.userId !== this.id ) { - hooks.newReadCursor(cursor) + hooks.onNewReadCursor(cursor) } } }, @@ -452,10 +452,10 @@ export class CurrentUser { hooks: { newCursor: cursor => { if ( - hooks.newReadCursor && cursor.type === 0 && + hooks.onNewReadCursor && cursor.type === 0 && this.isMemberOf(cursor.roomId) ) { - hooks.newReadCursor(cursor) + hooks.onNewReadCursor(cursor) } } }, diff --git a/src/message-subscription.js b/src/message-subscription.js index f7fae7d..77e296b 100644 --- a/src/message-subscription.js +++ b/src/message-subscription.js @@ -66,8 +66,8 @@ export class MessageSubscription { flushBuffer = () => { while (!isEmpty(this.messageBuffer) && head(this.messageBuffer).ready) { const message = this.messageBuffer.shift().message - if (this.hooks.newMessage) { - this.hooks.newMessage(message) + if (this.hooks.onNewMessage) { + this.hooks.onNewMessage(message) } } } diff --git a/src/presence-subscription.js b/src/presence-subscription.js index e788c86..dd9bce0 100644 --- a/src/presence-subscription.js +++ b/src/presence-subscription.js @@ -82,9 +82,9 @@ export class PresenceSubscription { map(parsePresence, userStates) ) - onCameOnline = user => this.callRelevantHooks('userCameOnline', user) + onCameOnline = user => this.callRelevantHooks('onUserCameOnline', user) - onWentOffline = user => this.callRelevantHooks('userWentOffline', user) + onWentOffline = user => this.callRelevantHooks('onUserWentOffline', user) callRelevantHooks = (hookName, user) => { if (this.hooks[hookName]) { diff --git a/src/typing-indicators.js b/src/typing-indicators.js index 52febfd..1e88739 100644 --- a/src/typing-indicators.js +++ b/src/typing-indicators.js @@ -51,20 +51,20 @@ export class TypingIndicators { } onStarted = (room, user, hooks, roomHooks) => { - if (hooks.userStartedTyping) { - hooks.userStartedTyping(room, user) + if (hooks.onUserStartedTyping) { + hooks.onUserStartedTyping(room, user) } - if (roomHooks[room.id] && roomHooks[room.id].userStartedTyping) { - roomHooks[room.id].userStartedTyping(user) + if (roomHooks[room.id] && roomHooks[room.id].onUserStartedTyping) { + roomHooks[room.id].onUserStartedTyping(user) } } onStopped = (room, user, hooks, roomHooks) => { - if (hooks.userStoppedTyping) { - hooks.userStoppedTyping(room, user) + if (hooks.onUserStoppedTyping) { + hooks.onUserStoppedTyping(room, user) } - if (roomHooks[room.id] && roomHooks[room.id].userStoppedTyping) { - roomHooks[room.id].userStoppedTyping(user) + if (roomHooks[room.id] && roomHooks[room.id].onUserStoppedTyping) { + roomHooks[room.id].onUserStoppedTyping(user) } } } diff --git a/src/user-subscription.js b/src/user-subscription.js index b33be6e..f9556fa 100644 --- a/src/user-subscription.js +++ b/src/user-subscription.js @@ -69,8 +69,8 @@ export class UserSubscription { onAddedToRoom = ({ room: roomData }) => { const basicRoom = parseBasicRoom(roomData) this.roomStore.set(basicRoom.id, basicRoom).then(room => { - if (this.hooks.addedToRoom) { - this.hooks.addedToRoom(room) + if (this.hooks.onAddedToRoom) { + this.hooks.onAddedToRoom(room) } }) } @@ -78,8 +78,8 @@ export class UserSubscription { onRemovedFromRoom = ({ room_id: roomId }) => { this.roomStore.pop(roomId).then(room => { // room will be undefined if we left with leaveRoom - if (room && this.hooks.removedFromRoom) { - this.hooks.removedFromRoom(room) + if (room && this.hooks.onRemovedFromRoom) { + this.hooks.onRemovedFromRoom(room) } }) } @@ -87,14 +87,14 @@ export class UserSubscription { onUserJoined = ({ room_id: roomId, user_id: userId }) => { this.roomStore.addUserToRoom(roomId, userId).then(room => { this.userStore.get(userId).then(user => { - if (this.hooks.userJoinedRoom) { - this.hooks.userJoinedRoom(room, user) + if (this.hooks.onUserJoinedRoom) { + this.hooks.onUserJoinedRoom(room, user) } if ( this.roomSubscriptions[roomId] && - this.roomSubscriptions[roomId].hooks.userJoined + this.roomSubscriptions[roomId].hooks.onUserJoined ) { - this.roomSubscriptions[roomId].hooks.userJoined(user) + this.roomSubscriptions[roomId].hooks.onUserJoined(user) } }) }) @@ -103,14 +103,14 @@ export class UserSubscription { onUserLeft = ({ room_id: roomId, user_id: userId }) => { this.roomStore.removeUserFromRoom(roomId, userId).then(room => { this.userStore.get(userId).then(user => { - if (this.hooks.userLeftRoom) { - this.hooks.userLeftRoom(room, user) + if (this.hooks.onUserLeftRoom) { + this.hooks.onUserLeftRoom(room, user) } if ( this.roomSubscriptions[roomId] && - this.roomSubscriptions[roomId].hooks.userLeft + this.roomSubscriptions[roomId].hooks.onUserLeft ) { - this.roomSubscriptions[roomId].hooks.userLeft(user) + this.roomSubscriptions[roomId].hooks.onUserLeft(user) } }) }) @@ -119,16 +119,16 @@ export class UserSubscription { onRoomUpdated = ({ room: roomData }) => { const updates = parseBasicRoom(roomData) this.roomStore.update(updates.id, updates).then(room => { - if (this.hooks.roomUpdated) { - this.hooks.roomUpdated(room) + if (this.hooks.onRoomUpdated) { + this.hooks.onRoomUpdated(room) } }) } onRoomDeleted = ({ room_id: roomId }) => { this.roomStore.pop(roomId).then(room => { - if (room && this.hooks.roomDeleted) { - this.hooks.roomDeleted(room) + if (room && this.hooks.onRoomDeleted) { + this.hooks.onRoomDeleted(room) } }) } diff --git a/tests/main.js b/tests/main.js index c3ddea0..80e74cc 100644 --- a/tests/main.js +++ b/tests/main.js @@ -255,7 +255,7 @@ test('own read cursor undefined if not set', t => { test('new read cursor hook [Alice sets her read cursor in her room]', t => { Promise.all([fetchUser(t, 'alice'), fetchUser(t, 'alice', { - newReadCursor: cursor => { + onNewReadCursor: cursor => { t.equal(cursor.position, 42) t.equal(cursor.user.name, 'Alice') t.equal(cursor.room.name, `Alice's room`) @@ -285,7 +285,7 @@ test('get own read cursor', t => { test(`added to room hook [creates Bob & Bob's room]`, t => { let alice fetchUser(t, 'alice', { - addedToRoom: room => { + onAddedToRoom: room => { t.equal(room.name, `Bob's room`) t.true( any(r => r.id === room.id, alice.rooms), @@ -314,7 +314,7 @@ test(`added to room hook [creates Bob & Bob's room]`, t => { // (since then he will already be online) test('user came online hook (user sub)', t => { fetchUser(t, 'alice', { - userCameOnline: user => { + onUserCameOnline: user => { t.equal(user.id, 'bob') t.equal(user.presence.state, 'online') t.end() @@ -327,7 +327,7 @@ test('user came online hook (user sub)', t => { test('user went offline hook (user sub)', t => { fetchUser(t, 'alice', { - userWentOffline: user => { + onUserWentOffline: user => { t.equal(user.id, 'bob') t.equal(user.presence.state, 'offline') t.end() @@ -342,12 +342,12 @@ test('typing indicators (user sub)', t => { let started Promise.all([ fetchUser(t, 'alice', { - userStartedTyping: (room, user) => { + onUserStartedTyping: (room, user) => { started = Date.now() t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') }, - userStoppedTyping: (room, user) => { + onUserStoppedTyping: (room, user) => { t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') t.true(Date.now() - started > 1000, 'fired more than 1s after start') @@ -366,7 +366,7 @@ test('typing indicators (user sub)', t => { test('user left room hook (user sub) [removes Bob from his own room]', t => { fetchUser(t, 'alice', { - userLeftRoom: (room, user) => { + onUserLeftRoom: (room, user) => { t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') t.end() @@ -384,7 +384,7 @@ test('user left room hook (user sub) [removes Bob from his own room]', t => { test('user joined room hook (user sub) [Bob rejoins his own room]', t => { fetchUser(t, 'alice', { - userJoinedRoom: (room, user) => { + onUserJoinedRoom: (room, user) => { t.equal(room.id, bobsRoom.id) t.equal(user.id, 'bob') t.end() @@ -402,7 +402,7 @@ test('user joined room hook (user sub) [Bob rejoins his own room]', t => { test('room updated hook', t => { fetchUser(t, 'alice', { - roomUpdated: room => { + onRoomUpdated: room => { t.equal(room.id, bobsRoom.id) t.equal(room.name, `Bob's renamed room`) t.end() @@ -420,7 +420,7 @@ test('room updated hook', t => { test(`removed from room hook [removes Alice from Bob's room]`, t => { fetchUser(t, 'alice', { - removedFromRoom: room => { + onRemovedFromRoom: room => { t.equal(room.id, bobsRoom.id) t.end() } @@ -437,7 +437,7 @@ test(`removed from room hook [removes Alice from Bob's room]`, t => { test(`room deleted hook [destroys Alice's room]`, t => { fetchUser(t, 'alice', { - roomDeleted: room => { + onRoomDeleted: room => { t.equal(room.id, alicesRoom.id) t.end() } @@ -668,7 +668,7 @@ test('subscribe to room and fetch initial messages', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - newMessage: concatBatch(4, messages => { + onNewMessage: concatBatch(4, messages => { t.deepEqual(map(m => m.text, messages), ['hello', 'hey', 'hi', 'ho']) t.equal(messages[0].sender.name, 'Alice') t.equal(messages[0].room.name, `Bob's new room`) @@ -685,7 +685,7 @@ test('subscribe to room and fetch last two message only', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - newMessage: concatBatch(2, messages => { + onNewMessage: concatBatch(2, messages => { t.deepEqual(map(m => m.text, messages), ['hi', 'ho']) t.end() }) @@ -701,7 +701,7 @@ test('subscribe to room and receive sent messages', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - newMessage: concatBatch(3, messages => { + onNewMessage: concatBatch(3, messages => { t.deepEqual(map(m => m.text, messages), ['yo', 'yoo', 'yooo']) t.equal(messages[0].sender.name, 'Alice') t.equal(messages[0].room.name, `Bob's new room`) @@ -720,7 +720,7 @@ test('unsubscribe from room', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - newMessage: once(m => { + onNewMessage: once(m => { endWithErr(t, 'should not be called after unsubscribe') }) }, @@ -859,7 +859,7 @@ test(`user joined hook [Carol joins Bob's room]`, t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - userJoined: once(user => { + onUserJoined: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.end() @@ -883,7 +883,7 @@ test('user came online hook', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - userCameOnline: once(user => { + onUserCameOnline: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.equal(user.presence.state, 'online') @@ -901,7 +901,7 @@ test('user went offline hook', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - userWentOffline: once(user => { + onUserWentOffline: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.equal(user.presence.state, 'offline') @@ -921,12 +921,12 @@ test('typing indicators', t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - userStartedTyping: once(user => { + onUserStartedTyping: once(user => { started = Date.now() t.equal(user.id, 'carol') t.equal(user.name, 'Carol') }), - userStoppedTyping: once(user => { + onUserStoppedTyping: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.true(Date.now() - started > 1000, 'fired more than 1s after start') @@ -949,7 +949,7 @@ test(`user left hook [removes Carol from Bob's room]`, t => { .then(alice => alice.subscribeToRoom({ roomId: bobsRoom.id, hooks: { - userLeft: once(user => { + onUserLeft: once(user => { t.equal(user.id, 'carol') t.equal(user.name, 'Carol') t.end() @@ -976,7 +976,7 @@ test(`new read cursor hook [Bob sets his read cursor in Alice's room]`, t => { .then(alice => alice.subscribeToRoom({ roomId: alicesRoom.id, hooks: { - newReadCursor: cursor => { + onNewReadCursor: cursor => { t.equal(cursor.position, 128) t.equal(cursor.user.name, 'Bob') t.equal(cursor.room.name, `Alice's new room`) @@ -1070,7 +1070,7 @@ test('[setup] promote Alice to admin', t => { test(`update room [renames Bob's room]`, t => { fetchUser(t, 'alice', { - roomUpdated: room => { + onRoomUpdated: room => { t.equal(room.id, bobsRoom.id) t.equal(room.name, `Bob's updated room`) t.end() @@ -1088,7 +1088,7 @@ test(`update room [renames Bob's room]`, t => { test(`delete room [deletes Bob's room]`, t => { let alice fetchUser(t, 'alice', { - roomDeleted: room => { + onRoomDeleted: room => { t.equal(room.id, bobsRoom.id) t.false( any(r => r.id === bobsRoom.id, alice.rooms), From f282852fd6c263132b83d8546e36e6db6254b936 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 13:43:03 +0000 Subject: [PATCH 97/99] 0.7.0-alpha.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d51341a..ffd2448 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "pusher-chatkit-client", "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", - "version": "0.7.0-alpha.7.react-native.1", + "version": "0.7.0-alpha.7", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From 36b73c5c16ec2d663c80075d7bcfb83052c4c0b7 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 15:06:11 +0000 Subject: [PATCH 98/99] changelog, 0.7.0 --- CHANGELOG.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 4 +-- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3ce129..eaf20e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,95 @@ This project adheres to [Semantic Versioning Scheme](http://semver.org) --- -## [Unreleased](https://github.com/pusher/chatkit-client-js/compare/0.6.2...HEAD) +## [Unreleased](https://github.com/pusher/chatkit-client-js/compare/0.7.0...HEAD) + +## 0.7.0 -- 2018-03-13 + +This version represents a radical departure from 0.6.X. The interface is very +different, and there's a good chance we'll miss some of the changes in this +log. If something isn't working after migration, the best place to look first +is probably the +[documentation](https://docs.pusher.com/chatkit/reference/javascript). + +### Changes + +- Methods with `onSuccess`, `onFailure` callbacks changed to return promises + instead. e.g. + +```javascript +chatManager + .connect() + .then(currentUser => {}) + .catch(err => {}) +``` + +- All methods take a single object parameter (see the + [documentation](https://docs.pusher.com/chatkit/reference/javascript) for + details on each method's arguments) + +- Delegates renamed to `hooks` throughout. e.g. + +```javascript +currentUser.subscribeToRoom({ + roomId, + hooks: { + onNewMessage: m => {} + } +}) +``` + +- Hooks all prefixed with `on`. e.g. `onNewMessage`, `onStartedTyping` + +- `cursorSet` hook renamed to `onNewCursor` + +- `authContext.queryParams` and `authContext.headers` both moved to the root + options object in the token provider. e.g. + +```javascript +const tokenProvider = new TokenProvider({ + url: 'your.auth.url', + queryParams: { + someKey: someValue, + ... + }, + headers: { + SomeHeader: 'some-value', + ... + } +}) +``` + +- `addUser` and `removeUser` renamed to `addUserToRoom` and `removeUserFromRoom` + +- methods that used to accept a `Room` object now accept a `roomId`. e.g. + +instead of + +```javascript +currentUser.subscribeToRoom(myRoom, hooks) // WRONG +``` + +do + +```javascript +currentUser.subscribeToRoom({ roomId: myRoom.id, hooks }) +``` + +- The behaviour of read cursors has changed: in particular cursors are now + accessed via `currentUser.readCursor` and set with + `currentUser.setReadCursor`. See the [Read Cursors section of the + documentation](https://docs.pusher.com/chatkit/reference/javascript#read-cursors) + for details. + +- Presence data is now accessable on any user object under `user.presence`. e.g. + +```javascript +const isOnline = user.presence.state === 'online' +``` + +- All users that share a common room membership are accesable under + `currentUser.users`, and all members of a room are accessable under + `room.users`. ## 0.6.2 -- 2018-02-05 diff --git a/package.json b/package.json index ffd2448..5eecd3a 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "pusher-chatkit-client", + "name": "@pusher/chatkit", "description": "Pusher Chatkit client library for browsers and react native", "main": "dist/web/chatkit.js", - "version": "0.7.0-alpha.7", + "version": "0.7.0", "author": "Pusher", "license": "MIT", "homepage": "https://github.com/pusher/chatkit-client-js", From b77674a3c31ef92fe7b86a44a5af2284593187e8 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 13 Mar 2018 15:12:00 +0000 Subject: [PATCH 99/99] point to @pusher/chatkit in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e932b10..32bdb69 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ For more information on the Chatkit service, [see here](https://pusher.com/chatk [yarn](https://yarnpkg.com/): ```sh -$ yarn add pusher-chatkit-client +$ yarn add @pusher/chatkit ``` ## Script tag ```html - + ``` ## Getting started