From e3ea45b393306f4144d9c9fba8d6a6f72992c29e Mon Sep 17 00:00:00 2001 From: Tony Anziano Date: Mon, 18 Nov 2019 14:15:38 -0800 Subject: [PATCH] Rewrote emulator/core package & moved to app/main. (#1989) --- CHANGELOG.md | 2 + lerna.json | 2 - package-lock.json | 2205 ++--- packages/app/client/package.json | 1 - .../state/actions/windowStateActions.spec.ts | 5 +- .../client/src/state/reducers/users.spec.ts | 6 +- .../src/state/reducers/windowState.spec.ts | 5 +- .../client/src/state/sagas/resourcesSagas.ts | 6 +- .../azureLoginPromptDialogContainer.ts | 5 +- .../botCreationDialogContainer.ts | 5 +- .../botSettingsEditorContainer.ts | 5 +- .../connectServicePromptDialogContainer.ts | 5 +- .../dataCollectionDialogContainer.ts | 5 +- .../getStartedWithCSDialogContainer.ts | 5 +- .../openBotDialog/openBotDialogContainer.ts | 5 +- .../openUrlDialog/openUrlDialogContainer.ts | 5 +- .../postMigrationDialogContainer.ts | 5 +- .../progressIndicatorContainer.ts | 5 +- .../resourcesSettingsContainer.ts | 5 +- .../secretPromptDialogContainer.ts | 5 +- .../dialogs/tabManager/tabManagerContainer.ts | 5 +- .../updateAvailableDialogContainer.ts | 5 +- .../updateUnavailableDialogContainer.ts | 5 +- .../appSettingsEditorContainer.ts | 5 +- .../emulator/chatPanel/chatPanelContainer.ts | 5 +- .../ui/editor/emulator/emulatorContainer.ts | 5 +- .../emulator/parts/chat/chatContainer.ts | 5 +- .../chat/outerActivityWrapperContainer.ts | 5 +- .../parts/chat/traceActivityContainer.ts | 5 +- .../parts/inspector/inspectorContainer.ts | 5 +- .../editor/emulator/parts/log/logContainer.ts | 5 +- .../emulator/parts/log/logEntryContainer.ts | 5 +- .../recentBotsList/recentBotsListContainer.ts | 5 +- .../welcomePage/howToBuildABotContainer.ts | 5 +- .../welcomePage/welcomePageContainer.ts | 5 +- .../src/ui/shell/appMenu/appMenu.spec.tsx | 6 +- .../src/ui/shell/appMenu/appMenuContainer.ts | 5 +- .../botNotOpenExplorerContainer.ts | 5 +- .../endpointEditor/endpointEditorContainer.ts | 5 +- .../endpointExplorerContainer.ts | 5 +- .../notificationsExplorer/notification.tsx | 5 +- .../notificationsExplorer.tsx | 5 +- .../resourceExplorerContainer.ts | 5 +- .../connectedServiceEditorContainer.ts | 5 +- .../connectedServiceEditor/kvPair.spec.tsx | 24 +- .../connectedServiceEditor/kvPair.tsx | 15 +- .../connectedServicePickerContainer.ts | 5 +- .../servicesExplorerContainer.ts | 5 +- .../app/client/src/ui/shell/mainContainer.ts | 5 +- .../shell/mdi/documents/documentsContainer.ts | 5 +- .../client/src/ui/shell/mdi/mdiContainer.ts | 5 +- .../src/ui/shell/mdi/tab/tabContainer.ts | 5 +- .../ui/shell/mdi/tabBar/tabBarContainer.ts | 5 +- .../contentOverlay/contentOverlay.tsx | 5 +- .../leftContentOverlay/leftContentOverlay.tsx | 5 +- .../rightContentOverlay.tsx | 5 +- .../src/ui/shell/navBar/navBarContainer.ts | 5 +- packages/app/main/package-lock.json | 808 +- packages/app/main/package.json | 5 +- packages/app/main/src/appMenuBuilder.spec.ts | 1 + packages/app/main/src/appUpdater.spec.ts | 7 + packages/app/main/src/botFrameworkService.ts | 91 - packages/app/main/src/botHelpers.ts | 2 +- .../app/main/src/commands/botCommands.spec.ts | 22 +- packages/app/main/src/commands/botCommands.ts | 6 +- .../main/src/commands/clientInitCommands.ts | 5 +- .../src/commands/emulatorCommands.spec.ts | 61 +- .../app/main/src/commands/emulatorCommands.ts | 42 +- .../app/main/src/commands/oauthCommands.ts | 8 +- packages/app/main/src/emulator.ts | 56 +- packages/app/main/src/main.ts | 2 + packages/app/main/src/ngrokService.spec.ts | 33 +- packages/app/main/src/ngrokService.ts | 13 +- packages/app/main/src/restServer.spec.ts | 195 - packages/app/main/src/restServer.ts | 196 - .../src/server/constants}/authEndpoints.ts | 0 packages/app/main/src/server/restServer.ts | 289 + .../handlers/getAttachment.spec.ts | 203 + .../attachments/handlers}/getAttachment.ts | 23 +- .../handlers/getAttachmentInfo.spec.ts | 146 + .../handlers}/getAttachmentInfo.ts | 12 +- .../mountAttachmentsRoutes.spec.ts} | 34 +- .../attachments/mountAttachmentsRoutes.ts | 45 + .../attachments/types}/attachmentParams.ts | 0 .../sendBotStateDeprecationMessage.spec.ts | 52 + .../sendBotStateDeprecationMessage.ts} | 14 +- .../botState/mountBotStateRoutes.spec.ts | 57 + .../channel/botState/mountBotStateRoutes.ts} | 18 +- .../handlers/createConversation.spec.ts | 109 + .../handlers}/createConversation.ts | 31 +- .../handlers/deleteActivity.spec.ts | 88 + .../conversations/handlers/deleteActivity.ts} | 29 +- .../createConversationValidator.spec.ts | 86 + .../createConversationValidator.ts | 47 +- .../handlers/getActivityMembers.spec.ts | 83 + .../handlers/getActivityMembers.ts | 48 + .../handlers/getBotEndpoint.spec.ts | 119 + .../conversations/handlers}/getBotEndpoint.ts | 19 +- .../handlers/getConversation.spec.ts | 84 + .../handlers/getConversation.ts} | 16 +- .../handlers/getConversationMembers.spec.ts} | 73 +- .../handlers/getConversationMembers.ts} | 25 +- .../handlers/getConversations.spec.ts | 137 + .../handlers}/getConversations.ts | 14 +- .../handlers}/replyToActivity.spec.ts | 30 +- .../handlers}/replyToActivity.ts | 29 +- .../sendActivityToConversation.spec.ts | 89 + .../handlers}/sendActivityToConversation.ts | 33 +- .../sendHistoryToConversation.spec.ts} | 49 +- .../handlers/sendHistoryToConversation.ts} | 38 +- .../handlers/updateActivity.spec.ts | 101 + .../conversations/handlers/updateActivity.ts} | 53 +- .../handlers/uploadAttachment.spec.ts | 88 + .../handlers}/uploadAttachment.ts | 12 +- .../mountConversationsRoutes.spec.ts | 179 + .../conversations/mountConversationsRoutes.ts | 126 + .../types}/conversationAPIPathParameters.ts | 4 +- .../session/handlers/getSessionId.spec.ts} | 20 +- .../channel/session/handlers}/getSessionId.ts | 11 +- .../session/handlers/tokenRedirect.spec.ts | 61 + .../channel/session/handlers/tokenRedirect.ts | 50 + .../session/mountSessionRoutes.spec.ts | 54 + .../channel/session/mountSessionRoutes.ts} | 15 +- .../handlers/emulateOAuthCards.spec.ts | 79 + .../userToken/handlers/emulateOAuthCards.ts | 55 + .../userToken/handlers/getToken.spec.ts | 105 + .../channel/userToken/handlers}/getToken.ts | 48 +- .../userToken/handlers/signOut.spec.ts | 80 + .../channel/userToken/handlers/signOut.ts} | 33 +- .../userToken/handlers/tokenResponse.spec.ts | 135 + .../userToken/handlers}/tokenResponse.ts | 22 +- .../userToken/mountUserTokenRoutes.spec.ts | 99 + .../userToken/mountUserTokenRoutes.ts} | 51 +- .../channel}/userToken/tokenCache.spec.ts | 0 .../routes/channel}/userToken/tokenCache.ts | 2 +- .../channel/userToken/types}/TokenParams.ts | 0 .../channel/userToken/types}/TokenResponse.ts | 0 .../directLine/handlers/getAcivities.spec.ts | 79 + .../directLine/handlers/getActivities.ts} | 32 +- .../handlers/getConversation.spec.ts | 57 + .../directLine/handlers/getConversation.ts} | 11 +- .../directLine/handlers/options.spec.ts} | 22 +- .../routes/directLine/handlers}/options.ts | 14 +- .../directLine/handlers/postActivity.spec.ts | 253 + .../directLine/handlers}/postActivity.ts | 18 +- .../handlers/reconnectToConversation.spec.ts | 91 + .../handlers}/reconnectToConversation.ts | 12 +- .../handlers/startConversation.spec.ts | 217 + .../directLine/handlers}/startConversation.ts | 16 +- .../routes/directLine/handlers/stream.spec.ts | 52 + .../routes/directLine/handlers}/stream.ts | 14 +- .../routes/directLine/handlers/upload.spec.ts | 153 + .../routes/directLine/handlers}/upload.ts | 28 +- .../directLine/mountDirectLineRoutes.spec.ts | 118 + .../directLine/mountDirectLineRoutes.ts | 87 + .../routes/emulator/handlers/addUsers.spec.ts | 90 + .../routes/emulator/handlers/addUsers.ts} | 34 +- .../emulator/handlers/contactAdded.spec.ts | 80 + .../routes/emulator/handlers/contactAdded.ts} | 26 +- .../emulator/handlers/contactRemoved.spec.ts | 80 + .../emulator/handlers/contactRemoved.ts} | 26 +- .../emulator/handlers/deleteUserData.spec.ts | 80 + .../emulator/handlers/deleteUserData.ts | 51 + .../handlers/getConversation.spec.ts} | 41 +- .../emulator/handlers/getConversation.ts} | 16 +- .../handlers/getConversationEndpoint.spec.ts | 133 + .../handlers}/getConversationEndpoint.ts | 12 +- .../routes/emulator/handlers/getUsers.ts | 50 + .../emulator/handlers/paymentComplete.spec.ts | 100 + .../emulator/handlers/paymentComplete.ts} | 36 +- .../routes/emulator/handlers/ping.spec.ts} | 62 +- .../server/routes/emulator/handlers/ping.ts | 51 + .../emulator/handlers/removeUsers.spec.ts | 52 + .../routes/emulator/handlers/removeUsers.ts} | 38 +- .../handlers/sendTokenResponse.spec.ts | 80 + .../emulator/handlers/sendTokenResponse.ts} | 30 +- .../emulator/handlers/sendTyping.spec.ts | 79 + .../routes/emulator/handlers/sendTyping.ts} | 28 +- .../handlers/updateShippingAddress.spec.ts | 100 + .../handlers/updateShippingAddress.ts | 53 + .../handlers/updateShippingOption.spec.ts | 100 + .../emulator/handlers/updateShippingOption.ts | 53 + .../emulator/mountEmulatorRoutes.spec.ts | 128 + .../routes/emulator/mountEmulatorRoutes.ts | 98 + .../botFrameworkAuthentication.spec.ts | 17 +- .../handlers}/botFrameworkAuthentication.ts | 14 +- .../routes/handlers}/getBotEndpoint.spec.ts | 19 +- .../server/routes/handlers}/getBotEndpoint.ts | 6 +- .../handlers}/stripEmptyBearerToken.spec.ts | 8 +- .../routes/handlers}/stripEmptyBearerToken.ts | 21 +- .../src/server/routes/mountAllRoutes.spec.ts | 84 + .../main/src/server/routes/mountAllRoutes.ts} | 41 +- .../src/server/state}/attachments.spec.ts | 10 +- .../main/src/server/state}/attachments.ts | 6 +- .../main/src/server/state}/botDataKey.spec.ts | 2 +- .../main/src/server/state}/botDataKey.ts | 2 +- .../src/server/state}/botEndpoint.spec.ts | 4 +- .../main/src/server/state}/botEndpoint.ts | 9 +- .../server/state}/consoleLogService.spec.ts | 2 +- .../src/server/state}/consoleLogService.ts | 2 +- .../src/server/state}/conversation.spec.ts | 36 +- .../main/src/server/state}/conversation.ts | 72 +- .../src/server/state}/conversationSet.spec.ts | 2 +- .../main/src/server/state}/conversationSet.ts | 14 +- .../src/server/state}/endpointSet.spec.ts | 23 +- .../main/src/server/state}/endpointSet.ts | 15 +- .../src/server/state}/loggerAdapter.spec.ts | 2 +- .../main/src/server/state}/loggerAdapter.ts | 2 +- .../app/main/src/server/state/serverState.ts | 49 + .../main/src/server/state}/users.spec.ts | 2 +- .../main/src/server/state}/users.ts | 2 +- .../src/server}/utils/activityVisitor.spec.ts | 3 +- .../main/src/server}/utils/activityVisitor.ts | 2 +- .../utils/approximateObjectSize.spec.ts | 3 +- .../server}/utils/approximateObjectSize.ts | 2 +- .../createAPIException.spec.ts} | 6 +- .../createResponse/createAPIException.ts} | 2 +- .../createConversationResponse.spec.ts} | 2 +- .../createConversationResponse.ts} | 5 +- .../createErrorResponse.spec.ts} | 2 +- .../createResponse/createErrorResponse.ts} | 2 +- .../createResourceResponse.spec.ts} | 2 +- .../createResponse/createResourceResponse.ts} | 2 +- .../src/server}/utils/jsonBodyParser.spec.ts | 18 +- .../main/src/server}/utils/jsonBodyParser.ts | 2 +- .../server}/utils/oauthClientEncoder.spec.ts | 2 +- .../src/server}/utils/oauthClientEncoder.ts | 4 +- .../server}/utils/oauthLinkEncoder.spec.ts | 12 +- .../src/server}/utils/oauthLinkEncoder.ts | 21 +- .../src/server}/utils/openIdMetadata.spec.ts | 2 +- .../main/src/server}/utils/openIdMetadata.ts | 2 +- .../src/server}/utils/paymentEncoder.spec.ts | 2 +- .../main/src/server}/utils/paymentEncoder.ts | 4 +- .../main/src/server}/utils/safeStringify.ts | 2 +- .../server}/utils/sendErrorResponse.spec.ts | 4 +- .../src/server}/utils/sendErrorResponse.ts | 4 +- .../server}/utils/statusCodeFamily.spec.ts | 2 +- .../src/server}/utils/statusCodeFamily.ts | 2 +- .../main/src/server}/utils/stringProvider.ts | 0 .../main/src/server}/utils/uniqueId.spec.ts | 2 +- .../main/src/server}/utils/uniqueId.ts | 2 +- .../state/actions/windowStateActions.spec.ts | 5 +- .../app/main/src/state/reducers/users.spec.ts | 6 +- .../src/state/reducers/windowState.spec.ts | 5 +- .../app/main/src/state/sagas/settingsSagas.ts | 6 +- .../src/utils/getLocalhostServiceUrl.spec.ts | 2 +- .../main/src/utils/getLocalhostServiceUrl.ts | 2 +- .../src/utils/openFileFromCommandLine.spec.ts | 5 +- packages/emulator/cli/.babelrc | 22 - packages/emulator/cli/.eslintrc.js | 6 - packages/emulator/cli/.gitignore | 5 - packages/emulator/cli/package-lock.json | 13 - packages/emulator/cli/package.json | 83 - packages/emulator/cli/src/index.ts | 149 - packages/emulator/cli/tsconfig.json | 8 - packages/emulator/core/.babelrc | 20 - packages/emulator/core/.eslintrc.js | 3 - packages/emulator/core/.gitignore | 4 - packages/emulator/core/package-lock.json | 8607 ----------------- packages/emulator/core/package.json | 101 - .../middleware/attachmentsMiddleware.spec.ts | 209 - .../src/attachments/registerRoutes.spec.ts | 72 - .../emulator/core/src/botEmulator.spec.ts | 151 - packages/emulator/core/src/botEmulator.ts | 125 - .../middleware/botstateMiddleware.spec.ts | 205 - .../src/botState/middleware/setUserData.ts | 59 - .../core/src/botState/registerRoutes.spec.ts | 150 - .../core/src/botState/registerRoutes.ts | 127 - .../conversationsMiddleware.spec.ts | 709 -- .../src/conversations/registerRoutes.spec.ts | 186 - .../core/src/conversations/registerRoutes.ts | 168 - .../middleware/directLineMiddleware.spec.ts | 507 - .../src/directLine/registerRoutes.spec.ts | 143 - .../core/src/directLine/registerRoutes.ts | 117 - .../src/emulator/middleware/contactRemoved.ts | 54 - .../src/emulator/middleware/deleteUserData.ts | 54 - .../getConversationEndpoint.spec.ts | 84 - .../emulator/middleware/paymentComplete.ts | 58 - .../core/src/emulator/middleware/ping.ts | 54 - .../core/src/emulator/middleware/typing.ts | 54 - .../middleware/updateShippingAddress.ts | 55 - .../middleware/updateShippingOption.ts | 55 - .../core/src/emulator/registerRoutes.spec.ts | 189 - .../core/src/emulator/registerRoutes.ts | 156 - .../core/src/facility/botState.spec.ts | 176 - .../emulator/core/src/facility/botState.ts | 133 - packages/emulator/core/src/index.ts | 39 - .../core/src/session/registerRoutes.ts | 61 - .../userToken/middleware/emulateOAuthCards.ts | 57 - .../core/src/userToken/middleware/signOut.ts | 56 - .../core/src/userToken/registerRoutes.spec.ts | 111 - .../core/src/userToken/registerRoutes.ts | 88 - packages/emulator/core/tsconfig.json | 7 - .../shared/src/types/botEmulatorOptions.ts | 41 - packages/sdk/shared/src/types/index.ts | 1 - packages/tools/package-lock.json | 774 -- 296 files changed, 8563 insertions(+), 17153 deletions(-) delete mode 100644 packages/app/main/src/botFrameworkService.ts delete mode 100644 packages/app/main/src/restServer.spec.ts delete mode 100644 packages/app/main/src/restServer.ts rename packages/{emulator/core/src => app/main/src/server/constants}/authEndpoints.ts (100%) create mode 100644 packages/app/main/src/server/restServer.ts create mode 100644 packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.spec.ts rename packages/{emulator/core/src/attachments/middleware => app/main/src/server/routes/channel/attachments/handlers}/getAttachment.ts (77%) create mode 100644 packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.spec.ts rename packages/{emulator/core/src/attachments/middleware => app/main/src/server/routes/channel/attachments/handlers}/getAttachmentInfo.ts (87%) rename packages/{emulator/core/src/session/registerRoutes.spec.ts => app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.spec.ts} (63%) create mode 100644 packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.ts rename packages/{emulator/core/src/attachments => app/main/src/server/routes/channel/attachments/types}/attachmentParams.ts (100%) create mode 100644 packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.spec.ts rename packages/{emulator/core/src/middleware/getFacility.ts => app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.ts} (79%) create mode 100644 packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.spec.ts rename packages/{emulator/core/src/botState/middleware/fetchBotData.ts => app/main/src/server/routes/channel/botState/mountBotStateRoutes.ts} (75%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/createConversation.ts (78%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.spec.ts rename packages/{emulator/core/src/emulator/middleware/contactAdded.ts => app/main/src/server/routes/channel/conversations/handlers/deleteActivity.ts} (71%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/errorCondition/createConversationValidator.ts (62%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.spec.ts create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.ts create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/getBotEndpoint.ts (85%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.spec.ts rename packages/{emulator/core/src/conversations/middleware/fetchConversation.ts => app/main/src/server/routes/channel/conversations/handlers/getConversation.ts} (76%) rename packages/{emulator/core/src/conversations/middleware/updateActivity.ts => app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.spec.ts} (52%) rename packages/{emulator/core/src/botState/middleware/getConversationData.ts => app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.ts} (75%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/getConversations.ts (86%) rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/replyToActivity.spec.ts (85%) rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/replyToActivity.ts (73%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/sendActivityToConversation.ts (68%) rename packages/{emulator/core/src/botState/middleware/setConversationData.ts => app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.spec.ts} (59%) rename packages/{emulator/core/src/emulator/middleware/addUsers.ts => app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.ts} (64%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.spec.ts rename packages/{emulator/core/src/conversations/middleware/sendHistoryToConversation.ts => app/main/src/server/routes/channel/conversations/handlers/updateActivity.ts} (59%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.spec.ts rename packages/{emulator/core/src/conversations/middleware => app/main/src/server/routes/channel/conversations/handlers}/uploadAttachment.ts (82%) create mode 100644 packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.spec.ts create mode 100644 packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.ts rename packages/{emulator/core/src/conversations => app/main/src/server/routes/channel/conversations/types}/conversationAPIPathParameters.ts (94%) rename packages/{emulator/core/src/middleware/getFacility.spec.ts => app/main/src/server/routes/channel/session/handlers/getSessionId.spec.ts} (79%) rename packages/{emulator/core/src/session/middleware => app/main/src/server/routes/channel/session/handlers}/getSessionId.ts (83%) create mode 100644 packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.spec.ts create mode 100644 packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.ts create mode 100644 packages/app/main/src/server/routes/channel/session/mountSessionRoutes.spec.ts rename packages/{emulator/core/src/directLine/middleware/getConversation.ts => app/main/src/server/routes/channel/session/mountSessionRoutes.ts} (78%) create mode 100644 packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.spec.ts create mode 100644 packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.ts create mode 100644 packages/app/main/src/server/routes/channel/userToken/handlers/getToken.spec.ts rename packages/{emulator/core/src/userToken/middleware => app/main/src/server/routes/channel/userToken/handlers}/getToken.ts (63%) create mode 100644 packages/app/main/src/server/routes/channel/userToken/handlers/signOut.spec.ts rename packages/{emulator/core/src/emulator/middleware/sendTokenResponse.ts => app/main/src/server/routes/channel/userToken/handlers/signOut.ts} (70%) create mode 100644 packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.spec.ts rename packages/{emulator/core/src/userToken/middleware => app/main/src/server/routes/channel/userToken/handlers}/tokenResponse.ts (73%) create mode 100644 packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.spec.ts rename packages/{emulator/cli/src/npmLogger.ts => app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.ts} (51%) rename packages/{emulator/core/src => app/main/src/server/routes/channel}/userToken/tokenCache.spec.ts (100%) rename packages/{emulator/core/src => app/main/src/server/routes/channel}/userToken/tokenCache.ts (97%) rename packages/{emulator/core/src/userToken => app/main/src/server/routes/channel/userToken/types}/TokenParams.ts (100%) rename packages/{emulator/core/src/userToken => app/main/src/server/routes/channel/userToken/types}/TokenResponse.ts (100%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/getAcivities.spec.ts rename packages/{emulator/core/src/botState/middleware/deleteStateForUser.ts => app/main/src/server/routes/directLine/handlers/getActivities.ts} (72%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/getConversation.spec.ts rename packages/{emulator/core/src/middleware/getRouteName.ts => app/main/src/server/routes/directLine/handlers/getConversation.ts} (80%) rename packages/{emulator/core/src/middleware/getRouteName.spec.ts => app/main/src/server/routes/directLine/handlers/options.spec.ts} (79%) rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/options.ts (83%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/postActivity.spec.ts rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/postActivity.ts (81%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.spec.ts rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/reconnectToConversation.ts (85%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/startConversation.spec.ts rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/startConversation.ts (88%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/stream.spec.ts rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/stream.ts (82%) create mode 100644 packages/app/main/src/server/routes/directLine/handlers/upload.spec.ts rename packages/{emulator/core/src/directLine/middleware => app/main/src/server/routes/directLine/handlers}/upload.ts (85%) create mode 100644 packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.spec.ts create mode 100644 packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/addUsers.spec.ts rename packages/{emulator/core/src/directLine/middleware/getActivities.ts => app/main/src/server/routes/emulator/handlers/addUsers.ts} (67%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/contactAdded.spec.ts rename packages/{emulator/core/src/botState/middleware/getPrivateConversationData.ts => app/main/src/server/routes/emulator/handlers/contactAdded.ts} (75%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/contactRemoved.spec.ts rename packages/{emulator/core/src/conversations/middleware/getActivityMembers.ts => app/main/src/server/routes/emulator/handlers/contactRemoved.ts} (74%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/deleteUserData.spec.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/deleteUserData.ts rename packages/{emulator/core/src/conversations/middleware/getConversationMembers.ts => app/main/src/server/routes/emulator/handlers/getConversation.spec.ts} (61%) rename packages/{emulator/core/src/emulator/middleware/fetchConversation.ts => app/main/src/server/routes/emulator/handlers/getConversation.ts} (77%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.spec.ts rename packages/{emulator/core/src/emulator/middleware => app/main/src/server/routes/emulator/handlers}/getConversationEndpoint.ts (82%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/getUsers.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/paymentComplete.spec.ts rename packages/{emulator/core/src/botState/middleware/setPrivateConversationData.ts => app/main/src/server/routes/emulator/handlers/paymentComplete.ts} (64%) rename packages/{emulator/core/src/emulator/middleware/removeUsers.ts => app/main/src/server/routes/emulator/handlers/ping.spec.ts} (54%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/ping.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/removeUsers.spec.ts rename packages/{emulator/core/src/conversations/middleware/deleteActivity.ts => app/main/src/server/routes/emulator/handlers/removeUsers.ts} (66%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.spec.ts rename packages/{emulator/core/src/emulator/middleware/getUsers.ts => app/main/src/server/routes/emulator/handlers/sendTokenResponse.ts} (72%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/sendTyping.spec.ts rename packages/{emulator/core/src/botState/middleware/getUserData.ts => app/main/src/server/routes/emulator/handlers/sendTyping.ts} (77%) create mode 100644 packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.spec.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.spec.ts create mode 100644 packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.ts create mode 100644 packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.spec.ts create mode 100644 packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.ts rename packages/{emulator/core/src/utils => app/main/src/server/routes/handlers}/botFrameworkAuthentication.spec.ts (97%) rename packages/{emulator/core/src/utils => app/main/src/server/routes/handlers}/botFrameworkAuthentication.ts (95%) rename packages/{emulator/core/src/middleware => app/main/src/server/routes/handlers}/getBotEndpoint.spec.ts (82%) rename packages/{emulator/core/src/middleware => app/main/src/server/routes/handlers}/getBotEndpoint.ts (91%) rename packages/{emulator/core/src/utils => app/main/src/server/routes/handlers}/stripEmptyBearerToken.spec.ts (89%) rename packages/{emulator/core/src/utils => app/main/src/server/routes/handlers}/stripEmptyBearerToken.ts (83%) create mode 100644 packages/app/main/src/server/routes/mountAllRoutes.spec.ts rename packages/{emulator/core/src/attachments/registerRoutes.ts => app/main/src/server/routes/mountAllRoutes.ts} (59%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/attachments.spec.ts (90%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/attachments.ts (93%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/botDataKey.spec.ts (97%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/botDataKey.ts (93%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/botEndpoint.spec.ts (99%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/botEndpoint.ts (97%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/consoleLogService.spec.ts (98%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/consoleLogService.ts (97%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/conversation.spec.ts (93%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/conversation.ts (90%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/conversationSet.spec.ts (98%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/conversationSet.ts (88%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/endpointSet.spec.ts (92%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/endpointSet.ts (88%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/loggerAdapter.spec.ts (98%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/loggerAdapter.ts (98%) create mode 100644 packages/app/main/src/server/state/serverState.ts rename packages/{emulator/core/src/facility => app/main/src/server/state}/users.spec.ts (98%) rename packages/{emulator/core/src/facility => app/main/src/server/state}/users.ts (98%) rename packages/{emulator/core/src => app/main/src/server}/utils/activityVisitor.spec.ts (99%) rename packages/{emulator/core/src => app/main/src/server}/utils/activityVisitor.ts (98%) rename packages/{emulator/core/src => app/main/src/server}/utils/approximateObjectSize.spec.ts (96%) rename packages/{emulator/core/src => app/main/src/server}/utils/approximateObjectSize.ts (96%) rename packages/{emulator/core/src/utils/createResponse/apiException.spec.ts => app/main/src/server/utils/createResponse/createAPIException.spec.ts} (91%) rename packages/{emulator/core/src/utils/createResponse/apiException.ts => app/main/src/server/utils/createResponse/createAPIException.ts} (94%) rename packages/{emulator/core/src/utils/createResponse/conversation.spec.ts => app/main/src/server/utils/createResponse/createConversationResponse.spec.ts} (95%) rename packages/{emulator/core/src/utils/createResponse/conversation.ts => app/main/src/server/utils/createResponse/createConversationResponse.ts} (92%) rename packages/{emulator/core/src/utils/createResponse/error.spec.ts => app/main/src/server/utils/createResponse/createErrorResponse.spec.ts} (96%) rename packages/{emulator/core/src/utils/createResponse/error.ts => app/main/src/server/utils/createResponse/createErrorResponse.ts} (94%) rename packages/{emulator/core/src/utils/createResponse/resource.spec.ts => app/main/src/server/utils/createResponse/createResourceResponse.spec.ts} (95%) rename packages/{emulator/core/src/utils/createResponse/resource.ts => app/main/src/server/utils/createResponse/createResourceResponse.ts} (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/jsonBodyParser.spec.ts (83%) rename packages/{emulator/core/src => app/main/src/server}/utils/jsonBodyParser.ts (96%) rename packages/{emulator/core/src => app/main/src/server}/utils/oauthClientEncoder.spec.ts (97%) rename packages/{emulator/core/src => app/main/src/server}/utils/oauthClientEncoder.ts (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/oauthLinkEncoder.spec.ts (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/oauthLinkEncoder.ts (90%) rename packages/{emulator/core/src => app/main/src/server}/utils/openIdMetadata.spec.ts (99%) rename packages/{emulator/core/src => app/main/src/server}/utils/openIdMetadata.ts (98%) rename packages/{emulator/core/src => app/main/src/server}/utils/paymentEncoder.spec.ts (97%) rename packages/{emulator/core/src => app/main/src/server}/utils/paymentEncoder.ts (94%) rename packages/{emulator/core/src => app/main/src/server}/utils/safeStringify.ts (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/sendErrorResponse.spec.ts (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/sendErrorResponse.ts (95%) rename packages/{emulator/core/src => app/main/src/server}/utils/statusCodeFamily.spec.ts (96%) rename packages/{emulator/core/src => app/main/src/server}/utils/statusCodeFamily.ts (94%) rename packages/{emulator/core/src => app/main/src/server}/utils/stringProvider.ts (100%) rename packages/{emulator/core/src => app/main/src/server}/utils/uniqueId.spec.ts (97%) rename packages/{emulator/core/src => app/main/src/server}/utils/uniqueId.ts (97%) delete mode 100644 packages/emulator/cli/.babelrc delete mode 100644 packages/emulator/cli/.eslintrc.js delete mode 100644 packages/emulator/cli/.gitignore delete mode 100644 packages/emulator/cli/package-lock.json delete mode 100644 packages/emulator/cli/package.json delete mode 100644 packages/emulator/cli/src/index.ts delete mode 100644 packages/emulator/cli/tsconfig.json delete mode 100644 packages/emulator/core/.babelrc delete mode 100644 packages/emulator/core/.eslintrc.js delete mode 100644 packages/emulator/core/.gitignore delete mode 100644 packages/emulator/core/package-lock.json delete mode 100644 packages/emulator/core/package.json delete mode 100644 packages/emulator/core/src/attachments/middleware/attachmentsMiddleware.spec.ts delete mode 100644 packages/emulator/core/src/attachments/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/botEmulator.spec.ts delete mode 100644 packages/emulator/core/src/botEmulator.ts delete mode 100644 packages/emulator/core/src/botState/middleware/botstateMiddleware.spec.ts delete mode 100644 packages/emulator/core/src/botState/middleware/setUserData.ts delete mode 100644 packages/emulator/core/src/botState/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/botState/registerRoutes.ts delete mode 100644 packages/emulator/core/src/conversations/middleware/conversationsMiddleware.spec.ts delete mode 100644 packages/emulator/core/src/conversations/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/conversations/registerRoutes.ts delete mode 100644 packages/emulator/core/src/directLine/middleware/directLineMiddleware.spec.ts delete mode 100644 packages/emulator/core/src/directLine/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/directLine/registerRoutes.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/contactRemoved.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/deleteUserData.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/getConversationEndpoint.spec.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/paymentComplete.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/ping.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/typing.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/updateShippingAddress.ts delete mode 100644 packages/emulator/core/src/emulator/middleware/updateShippingOption.ts delete mode 100644 packages/emulator/core/src/emulator/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/emulator/registerRoutes.ts delete mode 100644 packages/emulator/core/src/facility/botState.spec.ts delete mode 100644 packages/emulator/core/src/facility/botState.ts delete mode 100644 packages/emulator/core/src/index.ts delete mode 100644 packages/emulator/core/src/session/registerRoutes.ts delete mode 100644 packages/emulator/core/src/userToken/middleware/emulateOAuthCards.ts delete mode 100644 packages/emulator/core/src/userToken/middleware/signOut.ts delete mode 100644 packages/emulator/core/src/userToken/registerRoutes.spec.ts delete mode 100644 packages/emulator/core/src/userToken/registerRoutes.ts delete mode 100644 packages/emulator/core/tsconfig.json delete mode 100644 packages/sdk/shared/src/types/botEmulatorOptions.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 499582127..39e637c39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Removed - [main] Removed unused `VersionManager` class in PR [1991](https://github.com/microsoft/BotFramework-Emulator/pull/1991) +- [main] Rewrote the `emulator/core` package and removed the `emulator/cli` package in PR [1989](https://github.com/microsoft/BotFramework-Emulator/pull/1989) + ## v4.6.0 - 2019 - 10 - 31 ## Added - [main] Added End-to-End tests using Spectron in PR [1696](https://github.com/microsoft/BotFramework-Emulator/pull/1696) diff --git a/lerna.json b/lerna.json index a1a4d420b..c38cb02cd 100644 --- a/lerna.json +++ b/lerna.json @@ -4,8 +4,6 @@ "packages/app/client", "packages/app/main", "packages/app/shared", - "packages/emulator/cli", - "packages/emulator/core", "packages/sdk/client", "packages/sdk/shared", "packages/sdk/ui-react", diff --git a/package-lock.json b/package-lock.json index 5656699d5..90d90e495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,9 +29,9 @@ } }, "@babel/cli": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.6.4.tgz", - "integrity": "sha512-tqrDyvPryBM6xjIyKKUwr3s8CzmmYidwgdswd7Uc/Cv0ogZcuS1TYQTLx/eWKP3UbJ6JxZAiYlBZabXm/rtRsQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.7.0.tgz", + "integrity": "sha512-jECEqAq6Ngf3pOhLSg7od9WKyrIacyh1oNNYtRXNn+ummSHCTXBamGywOAtiae34Vk7zKuQNnLvo2BKTMCoV4A==", "dev": true, "requires": { "chokidar": "^2.1.8", @@ -40,12 +40,17 @@ "fs-readdir-recursive": "^1.1.0", "glob": "^7.0.0", "lodash": "^4.17.13", - "mkdirp": "^0.5.1", - "output-file-sync": "^2.0.0", + "make-dir": "^2.1.0", "slash": "^2.0.0", "source-map": "^0.5.0" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -63,18 +68,18 @@ } }, "@babel/core": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.2.tgz", + "integrity": "sha512-eeD7VEZKfhK1KUXGiyPFettgF3m513f8FoBSWiQ1xTvl1RAopLs42Wp9+Ze911I6H0N9lNqJMDgoZT7gHsipeQ==", "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.4", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.4", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.3", - "@babel/types": "^7.6.3", - "convert-source-map": "^1.1.0", + "@babel/generator": "^7.7.2", + "@babel/helpers": "^7.7.0", + "@babel/parser": "^7.7.2", + "@babel/template": "^7.7.0", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.7.2", + "convert-source-map": "^1.7.0", "debug": "^4.1.0", "json5": "^2.1.0", "lodash": "^4.17.13", @@ -107,156 +112,203 @@ } }, "@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.2.tgz", + "integrity": "sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ==", "requires": { - "@babel/types": "^7.6.3", + "@babel/types": "^7.7.2", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.0.tgz", + "integrity": "sha512-k50CQxMlYTYo+GGyUGFwpxKVtxVJi9yh61sXZji3zYHccK9RYliZGSTOgci85T+r+0VFN2nWbGM04PIqwfrpMg==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.0" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.0.tgz", + "integrity": "sha512-Cd8r8zs4RKDwMG/92lpZcnn5WPQ3LAMQbCw42oqUh4s7vsSN5ANUZjMel0OOnxDLq57hoDDbai+ryygYfCTOsw==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-builder-react-jsx": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", - "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.0.tgz", + "integrity": "sha512-LSln3cexwInTMYYoFeVLKnYPPMfWNJ8PubTBs3hkh7wCu9iBaqq1OOyW+xGmEdLxT1nhsl+9SJ+h2oUDYz0l2A==", "dev": true, "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.7.0", "esutils": "^2.0.0" } }, "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.0.tgz", + "integrity": "sha512-Su0Mdq7uSSWGZayGMMQ+z6lnL00mMCnGAbO/R0ZO9odIdB/WNU/VfQKqMQU0fdIsxQYbRjDM4BixIa93SQIpvw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/helper-hoist-variables": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.6.0.tgz", - "integrity": "sha512-O1QWBko4fzGju6VoVvrZg0RROCVifcLxiApnGP3OWfWzvxRZFCoBD81K5ur5e3bVY2Vf/5rIJm8cqPKn8HUJng==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.0.tgz", + "integrity": "sha512-MZiB5qvTWoyiFOgootmRSDV1udjIqJW/8lmxgzKq6oDqxdmHUjeP2ZUOmgHdYjmUVNABqRrHjYAYRvj8Eox/UA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-function-name": "^7.7.0", + "@babel/helper-member-expression-to-functions": "^7.7.0", + "@babel/helper-optimise-call-expression": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4" + "@babel/helper-replace-supers": "^7.7.0", + "@babel/helper-split-export-declaration": "^7.7.0" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.2.tgz", + "integrity": "sha512-pAil/ZixjTlrzNpjx+l/C/wJk002Wo7XbbZ8oujH/AoJ3Juv0iN/UTcPUHXKMFLqsfS0Hy6Aow8M31brUYBlQQ==", + "dev": true, + "requires": { + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } } }, "@babel/helper-define-map": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", - "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.0.tgz", + "integrity": "sha512-kPKWPb0dMpZi+ov1hJiwse9dWweZsz3V9rP4KdytnX1E7z3cTNmFGglwklzFPuqIcHLIY3bgKSs4vkwXXdflQA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.5.5", + "@babel/helper-function-name": "^7.7.0", + "@babel/types": "^7.7.0", "lodash": "^4.17.13" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.0.tgz", + "integrity": "sha512-CDs26w2shdD1urNUAji2RJXyBFCaR+iBEGnFz3l7maizMkQe3saVw9WtjG1tz8CwbjvlFnaSLVhgnu1SWaherg==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz", + "integrity": "sha512-tDsJgMUAP00Ugv8O2aGEua5I2apkaQO7lBGUq1ocwN3G23JE5Dcq0uh3GvFTChPa4b40AWiAsLvCZOA2rdnQ7Q==", "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "^7.7.0", + "@babel/template": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.0.tgz", + "integrity": "sha512-tLdojOTz4vWcEnHWHCuPN5P85JLZWbm5Fx5ZsMEMPhF3Uoe3O7awrbM2nQ04bDOUToH/2tH/ezKEOR8zEYzqyw==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.0" } }, "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.0.tgz", + "integrity": "sha512-LUe/92NqsDAkJjjCEWkNe+/PcpnisvnqdlRe19FahVapa4jndeuJ+FBiTX1rcAKWKcJGE+C3Q3tuEuxkSmCEiQ==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.0" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", - "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.0.tgz", + "integrity": "sha512-QaCZLO2RtBcmvO/ekOLp8p7R5X2JriKRizeDpm5ChATAFWrrYDcDxPuCIBXKyBjY+i1vYSdcUTMIb8psfxHDPA==", "dev": true, "requires": { - "@babel/types": "^7.5.5" + "@babel/types": "^7.7.0" } }, "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz", + "integrity": "sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw==", "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.0" } }, "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.0.tgz", + "integrity": "sha512-rXEefBuheUYQyX4WjV19tuknrJFwyKw0HgzRwbkyTbB+Dshlq7eqkWbyjzToLrMZk/5wKVKdWFluiAsVkHXvuQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", + "@babel/helper-module-imports": "^7.7.0", + "@babel/helper-simple-access": "^7.7.0", + "@babel/helper-split-export-declaration": "^7.7.0", + "@babel/template": "^7.7.0", + "@babel/types": "^7.7.0", "lodash": "^4.17.13" } }, "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.0.tgz", + "integrity": "sha512-48TeqmbazjNU/65niiiJIJRc5JozB8acui1OS7bSd6PgxfuovWsvjfWSzlgx+gPFdVveNzUdpdIg5l56Pl5jqg==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.0" } }, "@babel/helper-plugin-utils": { @@ -274,68 +326,68 @@ } }, "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.0.tgz", + "integrity": "sha512-pHx7RN8X0UNHPB/fnuDnRXVZ316ZigkO8y8D835JlZ2SSdFKb6yH9MIYRU4fy/KPe5sPHDFOPvf8QLdbAGGiyw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.7.0", + "@babel/helper-wrap-function": "^7.7.0", + "@babel/template": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-replace-supers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", - "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.0.tgz", + "integrity": "sha512-5ALYEul5V8xNdxEeWvRsBzLMxQksT7MaStpxjJf9KsnLxpAKBtfw5NeMKZJSYDa0lKdOcy0g+JT/f5mPSulUgg==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" + "@babel/helper-member-expression-to-functions": "^7.7.0", + "@babel/helper-optimise-call-expression": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.0.tgz", + "integrity": "sha512-AJ7IZD7Eem3zZRuj5JtzFAptBw7pMlS3y8Qv09vaBWoFsle0d1kAn5Wq6Q9MyBXITPOKnxwkZKoAm4bopmv26g==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.0.tgz", + "integrity": "sha512-HgYSI8rH08neWlAH3CcdkFg9qX9YsZysZI5GD8LjhQib/mM0jGOZOVkoUiiV2Hu978fRtjtsGsW6w0pKHUWtqA==", "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.0" } }, "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.0.tgz", + "integrity": "sha512-sd4QjeMgQqzshSjecZjOp8uKfUtnpmCyQhKQrVJBBgeHAB/0FPi33h3AbVlVp07qQtMD4QgYSzaMI7VwncNK/w==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-function-name": "^7.7.0", + "@babel/template": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.0.tgz", + "integrity": "sha512-VnNwL4YOhbejHb7x/b5F39Zdg5vIQpUUNzJwx0ww1EcVRt41bbGRZWhAURrfY32T5zTT3qwNOQFWpn+P0i0a2g==", "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" + "@babel/template": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/highlight": { @@ -349,46 +401,46 @@ } }, "@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==" + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.3.tgz", + "integrity": "sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A==" }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.0.tgz", + "integrity": "sha512-ot/EZVvf3mXtZq0Pd0+tSOfGWMizqmOohXmNZg6LNFjHOV+wOPv7BvVYh8oPR8LhpIP3ye8nNooKL50YRWxpYA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/helper-remap-async-to-generator": "^7.7.0", "@babel/plugin-syntax-async-generators": "^7.2.0" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz", - "integrity": "sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.0.tgz", + "integrity": "sha512-tufDcFA1Vj+eWvwHN+jvMN6QsV5o+vUlytNKrbMiCeDL0F2j92RURzUsUMWE5EJkLyWxjdUslCsMQa9FWth16A==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.5.5", + "@babel/helper-create-class-features-plugin": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-proposal-decorators": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.6.0.tgz", - "integrity": "sha512-ZSyYw9trQI50sES6YxREXKu+4b7MAg6Qx2cvyDDYjP2Hpzd3FleOUwC9cqn1+za8d0A2ZU8SHujxFao956efUg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.7.0.tgz", + "integrity": "sha512-dMCDKmbYFQQTn1+VJjl5hbqlweuHl5oDeMU9B1Q7oAWi0mHxjQQDHdJIK6iW76NE1KJT3zA6dDU3weR1WT5D4A==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.6.0", + "@babel/helper-create-class-features-plugin": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-decorators": "^7.2.0" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", - "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.0.tgz", + "integrity": "sha512-7poL3Xi+QFPC7sGAzEIbXUyYzGJwbc2+gSD0AkiC5k52kH2cqHdqxm5hNFfLW3cRSTcx9bN0Fl7/6zWcLLnKAQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -426,51 +478,13 @@ } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", - "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.0.tgz", + "integrity": "sha512-mk34H+hp7kRBWJOOAR0ZMGCydgKMD4iN9TpDRp3IIcbunltxEY89XSimc6WbtSLCDrwcdy/EEw7h5CFCzxTchw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } + "@babel/helper-create-regexp-features-plugin": "^7.7.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-async-generators": { @@ -535,6 +549,15 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.0.tgz", + "integrity": "sha512-hi8FUNiFIY1fnUI2n1ViB1DR0R4QeK4iHcTlW6aJkrPoTdb8Rf1EMQ6GT3f67DDkYyWgew9DFoOZ6gOoEsdzTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/plugin-syntax-typescript": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", @@ -554,14 +577,14 @@ } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", - "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.0.tgz", + "integrity": "sha512-vLI2EFLVvRBL3d8roAMqtVY0Bm9C1QzLkdS57hiKrjUBSqsQYrBsMCeOg/0KK7B0eK9V71J5mWcha9yyoI2tZw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-module-imports": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-remap-async-to-generator": "^7.7.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -584,18 +607,18 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", - "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.0.tgz", + "integrity": "sha512-/b3cKIZwGeUesZheU9jNYcwrEA7f/Bo4IdPmvp7oHgvks2majB5BoT5byAql44fiNQYOPzhk2w8DbgfuafkMoA==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.5.5", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-annotate-as-pure": "^7.7.0", + "@babel/helper-define-map": "^7.7.0", + "@babel/helper-function-name": "^7.7.0", + "@babel/helper-optimise-call-expression": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/helper-replace-supers": "^7.7.0", + "@babel/helper-split-export-declaration": "^7.7.0", "globals": "^11.1.0" } }, @@ -618,51 +641,13 @@ } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", - "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.0.tgz", + "integrity": "sha512-3QQlF7hSBnSuM1hQ0pS3pmAbWLax/uGNCbPBND9y+oJ4Y776jsyujG2k0Sn2Aj2a0QwVOiOFL5QVPA7spjvzSA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } + "@babel/helper-create-regexp-features-plugin": "^7.7.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-duplicate-keys": { @@ -694,12 +679,12 @@ } }, "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.0.tgz", + "integrity": "sha512-P5HKu0d9+CzZxP5jcrWdpe7ZlFDe24bmqP6a6X8BHEBl/eizAsY8K6LX8LASZL0Jxdjm5eEfzp+FIrxCm/p8bA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", + "@babel/helper-function-name": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0" } }, @@ -744,14 +729,14 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.0.tgz", + "integrity": "sha512-KEMyWNNWnjOom8vR/1+d+Ocz/mILZG/eyHHO06OuBQ2aNhxT62fr4y6fGOplRx+CxCSp3IFwesL8WdINfY/3kg==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-module-transforms": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-simple-access": "^7.7.0", "babel-plugin-dynamic-import-node": "^2.3.0" }, "dependencies": { @@ -767,12 +752,12 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", - "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.0.tgz", + "integrity": "sha512-ZAuFgYjJzDNv77AjXRqzQGlQl4HdUM6j296ee4fwKVZfhDR9LAGxfvXjBkb06gNETPnN0sLqRm9Gxg4wZH6dXg==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-hoist-variables": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", "babel-plugin-dynamic-import-node": "^2.3.0" }, @@ -789,59 +774,22 @@ } }, "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.0.tgz", + "integrity": "sha512-u7eBA03zmUswQ9LQ7Qw0/ieC1pcAkbp5OQatbWUzY1PaBccvuJXUkYzoN1g7cqp7dbTu6Dp9bXyalBvD04AANA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-module-transforms": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz", - "integrity": "sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.0.tgz", + "integrity": "sha512-+SicSJoKouPctL+j1pqktRVCgy+xAch1hWWTMy13j0IflnyNjaoskj+DwRQFimHbLqO3sq2oN2CXMvXq3Bgapg==", "dev": true, "requires": { - "regexpu-core": "^4.6.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } + "@babel/helper-create-regexp-features-plugin": "^7.7.0" } }, "@babel/plugin-transform-new-target": { @@ -884,20 +832,20 @@ } }, "@babel/plugin-transform-react-jsx": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", - "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.0.tgz", + "integrity": "sha512-mXhBtyVB1Ujfy+0L6934jeJcSXj/VCg6whZzEcgiiZHNS0PGC7vUCsZDQCxxztkpIdF+dY1fUMcjAgEOC3ZOMQ==", "dev": true, "requires": { - "@babel/helper-builder-react-jsx": "^7.3.0", + "@babel/helper-builder-react-jsx": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-jsx": "^7.2.0" } }, "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.0.tgz", + "integrity": "sha512-AXmvnC+0wuj/cFkkS/HFHIojxH3ffSXE+ttulrqWjZZRaUOonfJc60e1wSNT4rV8tIunvu/R3wCp71/tLAa9xg==", "dev": true, "requires": { "regenerator-transform": "^0.14.0" @@ -982,115 +930,78 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.3.tgz", - "integrity": "sha512-aiWINBrPMSC3xTXRNM/dfmyYuPNKY/aexYqBgh0HBI5Y+WO5oRAqW/oROYeYHrF4Zw12r9rK4fMk/ZlAmqx/FQ==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.2.tgz", + "integrity": "sha512-UWhDaJRqdPUtdK1s0sKYdoRuqK0NepjZto2UZltvuCgMoMZmdjhgz5hcRokie/3aYEaSz3xvusyoayVaq4PjRg==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.6.0", + "@babel/helper-create-class-features-plugin": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-typescript": "^7.2.0" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", - "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.0.tgz", + "integrity": "sha512-RrThb0gdrNwFAqEAAx9OWgtx6ICK69x7i9tCnMdVrxQwSDp/Abu9DXFU5Hh16VP33Rmxh04+NGW28NsIkFvFKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - } - } + "@babel/helper-create-regexp-features-plugin": "^7.7.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/preset-env": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", - "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.1.tgz", + "integrity": "sha512-/93SWhi3PxcVTDpSqC+Dp4YxUu3qZ4m7I76k0w73wYfn7bGVuRIO4QUz95aJksbS+AD1/mT1Ie7rbkT0wSplaA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-module-imports": "^7.7.0", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-async-generator-functions": "^7.7.0", + "@babel/plugin-proposal-dynamic-import": "^7.7.0", "@babel/plugin-proposal-json-strings": "^7.2.0", "@babel/plugin-proposal-object-rest-spread": "^7.6.2", "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.6.2", + "@babel/plugin-proposal-unicode-property-regex": "^7.7.0", "@babel/plugin-syntax-async-generators": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-json-strings": "^7.2.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0", "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-syntax-top-level-await": "^7.7.0", "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-async-to-generator": "^7.7.0", "@babel/plugin-transform-block-scoped-functions": "^7.2.0", "@babel/plugin-transform-block-scoping": "^7.6.3", - "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-classes": "^7.7.0", "@babel/plugin-transform-computed-properties": "^7.2.0", "@babel/plugin-transform-destructuring": "^7.6.0", - "@babel/plugin-transform-dotall-regex": "^7.6.2", + "@babel/plugin-transform-dotall-regex": "^7.7.0", "@babel/plugin-transform-duplicate-keys": "^7.5.0", "@babel/plugin-transform-exponentiation-operator": "^7.2.0", "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.7.0", "@babel/plugin-transform-literals": "^7.2.0", "@babel/plugin-transform-member-expression-literals": "^7.2.0", "@babel/plugin-transform-modules-amd": "^7.5.0", - "@babel/plugin-transform-modules-commonjs": "^7.6.0", - "@babel/plugin-transform-modules-systemjs": "^7.5.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.3", + "@babel/plugin-transform-modules-commonjs": "^7.7.0", + "@babel/plugin-transform-modules-systemjs": "^7.7.0", + "@babel/plugin-transform-modules-umd": "^7.7.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.0", "@babel/plugin-transform-new-target": "^7.4.4", "@babel/plugin-transform-object-super": "^7.5.5", "@babel/plugin-transform-parameters": "^7.4.4", "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-regenerator": "^7.7.0", "@babel/plugin-transform-reserved-words": "^7.2.0", "@babel/plugin-transform-shorthand-properties": "^7.2.0", "@babel/plugin-transform-spread": "^7.6.2", "@babel/plugin-transform-sticky-regex": "^7.2.0", "@babel/plugin-transform-template-literals": "^7.4.4", "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.6.2", - "@babel/types": "^7.6.3", + "@babel/plugin-transform-unicode-regex": "^7.7.0", + "@babel/types": "^7.7.1", "browserslist": "^4.6.0", "core-js-compat": "^3.1.1", "invariant": "^2.2.2", @@ -1112,44 +1023,44 @@ } }, "@babel/preset-typescript": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.6.0.tgz", - "integrity": "sha512-4xKw3tTcCm0qApyT6PqM9qniseCE79xGHiUnNdKGdxNsGUc2X7WwZybqIpnTmoukg3nhPceI5KPNzNqLNeIJww==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.7.2.tgz", + "integrity": "sha512-1B4HthAelaLGfNRyrWqJtBEjXX1ulThCrLQ5B2VOtEAznWFIFXFJahgXImqppy66lx/Oh+cOSCQdJzZqh2Jh5g==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.6.0" + "@babel/plugin-transform-typescript": "^7.7.2" } }, "@babel/runtime": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", - "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", + "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", "requires": { "regenerator-runtime": "^0.13.2" } }, "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.0.tgz", + "integrity": "sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ==", "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" + "@babel/parser": "^7.7.0", + "@babel/types": "^7.7.0" } }, "@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.2.tgz", + "integrity": "sha512-TM01cXib2+rgIZrGJOLaHV/iZUAxf4A0dt5auY6KNZ+cm6aschuJGqKJM3ROTt3raPUdIDk9siAufIFEleRwtw==", "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", + "@babel/generator": "^7.7.2", + "@babel/helper-function-name": "^7.7.0", + "@babel/helper-split-export-declaration": "^7.7.0", + "@babel/parser": "^7.7.2", + "@babel/types": "^7.7.2", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -1171,9 +1082,9 @@ } }, "@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.2.tgz", + "integrity": "sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", @@ -1649,14 +1560,14 @@ } }, "@lerna/add": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.18.0.tgz", - "integrity": "sha512-Z5EaQbBnJn1LEPb0zb0Q2o9T8F8zOnlCsj6JYpY6aSke17UUT7xx0QMN98iBK+ueUHKjN/vdFdYlNCYRSIdujA==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.18.4.tgz", + "integrity": "sha512-R+9RmYrSbcmnmaFL2aB0HJtTq95ePEa0FMS4r4NnA7Xw07l5buVBPOfxv6P8kFrVvIcNpaa7S0Eo/KkbycMhKA==", "requires": { "@evocateur/pacote": "^9.6.3", - "@lerna/bootstrap": "3.18.0", + "@lerna/bootstrap": "3.18.4", "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", + "@lerna/filter-options": "3.18.4", "@lerna/npm-conf": "3.16.0", "@lerna/validation-error": "3.13.0", "dedent": "^0.7.0", @@ -1678,12 +1589,12 @@ } }, "@lerna/bootstrap": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.18.0.tgz", - "integrity": "sha512-3DZKWIaKvr7sUImoKqSz6eqn84SsOVMnA5QHwgzXiQjoeZ/5cg9x2r+Xj3+3w/lvLoh0j8U2GNtrIaPNis4bKQ==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.18.4.tgz", + "integrity": "sha512-mvqMyionPSqhbeGhoUQYEBTgbJ47LkONHfQ1AKBET0fJOjIZf6x0pWC17KvfCjsiE017325ySLKDH23z1Kb9ww==", "requires": { "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", + "@lerna/filter-options": "3.18.4", "@lerna/has-npm-version": "3.16.5", "@lerna/npm-install": "3.16.5", "@lerna/package-graph": "3.18.0", @@ -1707,11 +1618,6 @@ "semver": "^6.2.0" }, "dependencies": { - "get-port": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", - "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==" - }, "p-map": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", @@ -1725,15 +1631,14 @@ } }, "@lerna/changed": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.18.3.tgz", - "integrity": "sha512-xZW7Rm+DlDIGc0EvKGyJZgT9f8FFa4d52mr/Y752dZuXR2qRmf9tXhVloRG39881s2A6yi3jqLtXZggKhsQW4Q==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.18.4.tgz", + "integrity": "sha512-Ui4UsneDk9gCuJRfTpR5js+Ctt9Je+j+3Q4z7H7HhBn6WeWDTp6FBGJZ7SfrBCdQ47EKK27Mr95LbJ4I77xFfQ==", "requires": { "@lerna/collect-updates": "3.18.0", "@lerna/command": "3.18.0", - "@lerna/listable": "3.18.0", - "@lerna/output": "3.13.0", - "@lerna/version": "3.18.3" + "@lerna/listable": "3.18.4", + "@lerna/output": "3.13.0" } }, "@lerna/check-working-tree": { @@ -1790,12 +1695,12 @@ } }, "@lerna/clean": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.18.0.tgz", - "integrity": "sha512-BiwBELZNkarRQqj+v5NPB1aIzsOX+Y5jkZ9a5UbwHzEdBUQ5lQa0qaMLSOve/fSkaiZQxe6qnTyatN75lOcDMg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.18.4.tgz", + "integrity": "sha512-puuL0sBHIv3Tvq8cdu3kCGfRpdsXuaDGIRha33GVmRPfMBi2GN8nPPysVyWmP99PfgfafO6eT5R3jqXjvASAZA==", "requires": { "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", + "@lerna/filter-options": "3.18.4", "@lerna/prompt": "3.13.0", "@lerna/pulse-till-done": "3.13.0", "@lerna/rimraf-dir": "3.16.5", @@ -2179,13 +2084,13 @@ } }, "@lerna/exec": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.18.0.tgz", - "integrity": "sha512-hwkuzg1+38+pbzdZPhGtLIYJ59z498/BCNzR8d4/nfMYm8lFbw9RgJJajLcdbuJ9LJ08cZ93hf8OlzetL84TYg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.18.4.tgz", + "integrity": "sha512-BpBFxyCQXcfess9Nmj/OwQ9e1IhzPzNxqF5JK7dPIjko5oBn5Hm2EWVAcgUGSHKPZGLiOWPu3Wx/C92NtDBS1w==", "requires": { "@lerna/child-process": "3.16.5", "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", + "@lerna/filter-options": "3.18.4", "@lerna/run-topologically": "3.18.0", "@lerna/validation-error": "3.13.0", "p-map": "^2.1.0" @@ -2199,9 +2104,9 @@ } }, "@lerna/filter-options": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.18.0.tgz", - "integrity": "sha512-UGVcixs3TGzD8XSmFSbwUVVQnAjaZ6Rmt8Vuq2RcR98ULkGB1LiGNMY89XaNBhaaA8vx7yQWiLmJi2AfmD63Qg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.18.4.tgz", + "integrity": "sha512-4giVQD6tauRwweO/322LP2gfVDOVrt/xN4khkXyfkJDfcsZziFXq+668otD9KSLL8Ps+To4Fah3XbK0MoNuEvA==", "requires": { "@lerna/collect-updates": "3.18.0", "@lerna/filter-packages": "3.18.0", @@ -2407,20 +2312,20 @@ } }, "@lerna/list": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.18.0.tgz", - "integrity": "sha512-mpB7Q6T+n2CaiPFz0LuOE+rXphDfHm0mKIwShnyS/XDcii8jXv+z9Iytj8p3rfCH2I1L80j2qL6jWzyGy/uzKA==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.18.4.tgz", + "integrity": "sha512-bgtlhAwhjHOTLq0iIuPs30abeuLbwZvVB60Ym8kPp+chh939obKU3vy2KMyX+Gpxf8pzuQG+k986YXcUBvXVsw==", "requires": { "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", - "@lerna/listable": "3.18.0", + "@lerna/filter-options": "3.18.4", + "@lerna/listable": "3.18.4", "@lerna/output": "3.13.0" } }, "@lerna/listable": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-3.18.0.tgz", - "integrity": "sha512-9gLGKYNLSKeurD+sJ2RA+nz4Ftulr91U127gefz0RlmAPpYSjwcJkxwa0UfJvpQTXv9C7yzHLnn0BjyAQRjuew==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-3.18.4.tgz", + "integrity": "sha512-EKSsnST5k3dZfw+UTwBH1/sHQ1YfgjYjGxXCabyn55mMgc2GjoDekODMYzZ1TNF2NNy6RgIZ24X2JI8G22nZUw==", "requires": { "@lerna/query-graph": "3.18.0", "chalk": "^2.3.1", @@ -2702,9 +2607,9 @@ } }, "@lerna/publish": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.18.3.tgz", - "integrity": "sha512-XlfWOWIhaSK0Y2sX5ppNWI5Y3CDtlxMcQa1hTbZlC5rrDA6vD32iutbmH6Ix3c6wtvVbSkgA39GWsQEXxPS+7w==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.18.4.tgz", + "integrity": "sha512-Q+MqM5DUZvk+uT6hdEyO3khXET6LwED0YEuCu8fRwtHad03HkZ9i8PtTY5h8Sn6D6RCyCOlHTuf8O0KKAUy3ow==", "requires": { "@evocateur/libnpmaccess": "^3.1.2", "@evocateur/npm-registry-fetch": "^4.0.0", @@ -2727,7 +2632,7 @@ "@lerna/run-lifecycle": "3.16.2", "@lerna/run-topologically": "3.18.0", "@lerna/validation-error": "3.13.0", - "@lerna/version": "3.18.3", + "@lerna/version": "3.18.4", "figgy-pudding": "^3.5.1", "fs-extra": "^8.1.0", "npm-package-arg": "^6.1.0", @@ -2811,12 +2716,12 @@ } }, "@lerna/run": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.18.0.tgz", - "integrity": "sha512-sblxHBZ9djaaG7wefPcfEicDqzrB7CP1m/jIB0JvPEQwG4C2qp++ewBpkjRw/mBtjtzg0t7v0nNMXzaWYrQckQ==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.18.4.tgz", + "integrity": "sha512-u2ZNO2fVk5kVEpbpn4DLJZZxZ08LFnIFuaXJMAhxvOgvm12ZF2rabA9kZc3NXp5+DedG5nHHgyoyLVVbStKzBA==", "requires": { "@lerna/command": "3.18.0", - "@lerna/filter-options": "3.18.0", + "@lerna/filter-options": "3.18.4", "@lerna/npm-run-script": "3.16.5", "@lerna/output": "3.13.0", "@lerna/run-topologically": "3.18.0", @@ -2926,9 +2831,9 @@ } }, "@lerna/version": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.18.3.tgz", - "integrity": "sha512-IXXRlyM3Q/jrc+QZio+bgjG4ZaK+4LYmY4Yql1xyY0wZhAKsWP/Q6ho7e1EJNjNC5dUJO99Fq7qB05MkDf2OcQ==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.18.4.tgz", + "integrity": "sha512-+gR9H89qSP8iqzNi4tRVQUbWlFMOlhbY6+5TXkP72Ibb/z87O+C46DBqizSMVaPQYdSYjS1c9Xfa1oOhEWxGaw==", "requires": { "@lerna/check-working-tree": "3.16.5", "@lerna/child-process": "3.16.5", @@ -3010,9 +2915,9 @@ } }, "@microsoft/load-themed-styles": { - "version": "1.10.16", - "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.16.tgz", - "integrity": "sha512-S/d7Zx+ACN3Hu3BIAjWGefEu9xrLHUt2WRhd8WGJ3POkCQntCuyQmJhl72jJHFFGTKQc7iu3OCt4r7yTAOuwlQ==" + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.20.tgz", + "integrity": "sha512-auT1V9phsMScUQK/xVngVGQsABGG805/10RgP1TBbJvwoPoRq/Ed+ce47HoayFgqxtz5m/W/38OUNZpfuBqsCw==" }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", @@ -3023,17 +2928,34 @@ "glob-to-regexp": "^0.3.0" } }, + "@netflix/nerror": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.2.tgz", + "integrity": "sha512-c01MmkM3Oi0BkTV4odMpr+58uXlxRKUPcu1ONR+sU3YAFAW4pP1j2b0opS9jX+an3ldpBJtiompzAEFZdlc8YQ==", + "requires": { + "assert-plus": "^1.0.0", + "extsprintf": "^1.4.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "extsprintf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", + "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=" + } + } + }, "@nodelib/fs.stat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, "@octokit/endpoint": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.0.tgz", - "integrity": "sha512-TXYS6zXeBImNB9BVj+LneMDqXX+H0exkOpyXobvp92O3B1348QsKnNioISFKgOMsb3ibZvQGwCdpiwQd3KAjIA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz", + "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==", "requires": { - "@octokit/types": "^1.0.0", + "@octokit/types": "^2.0.0", "is-plain-object": "^3.0.0", "universal-user-agent": "^4.0.0" }, @@ -3059,13 +2981,13 @@ "integrity": "sha512-3wF5eueS5OHQYuAEudkpN+xVeUsg8vYEMMenEzLphUZ7PRZ8OJtDcsreL3ad9zxXmBbaFWzLmFcdob5CLyZftA==" }, "@octokit/request": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.0.tgz", - "integrity": "sha512-mMIeNrtYyNEIYNsKivDyUAukBkw0M5ckyJX56xoFRXSasDPCloIXaQOnaKNopzQ8dIOvpdq1ma8gmrS+h6O2OQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", + "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", "requires": { "@octokit/endpoint": "^5.5.0", "@octokit/request-error": "^1.0.1", - "@octokit/types": "^1.0.0", + "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "is-plain-object": "^3.0.0", "node-fetch": "^2.3.0", @@ -3089,18 +3011,19 @@ } }, "@octokit/request-error": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz", - "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz", + "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==", "requires": { + "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "@octokit/rest": { - "version": "16.34.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.34.1.tgz", - "integrity": "sha512-JUoS12cdktf1fv86rgrjC/RvYLuL+o7p57W7zX1x7ANFJ7OvdV8emvUNkFlcidEaOkYrxK3SoWgQFt3FhNmabA==", + "version": "16.35.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.35.0.tgz", + "integrity": "sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w==", "requires": { "@octokit/request": "^5.2.0", "@octokit/request-error": "^1.0.2", @@ -3117,18 +3040,11 @@ } }, "@octokit/types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-1.1.0.tgz", - "integrity": "sha512-t4ZD74UnNVMq6kZBDZceflRKK3q4o5PoCKMAGht0RK84W57tqonqKL3vCxJHtbGExdan9RwV8r7VJBZxIM1O7Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.1.tgz", + "integrity": "sha512-YDYgV6nCzdGdOm7wy43Ce8SQ3M5DMKegB8E5sTB/1xrxOdo2yS/KgUgML2N2ZGD621mkbdrAglwTyA4NDOlFFA==", "requires": { - "@types/node": "^12.11.1" - }, - "dependencies": { - "@types/node": { - "version": "12.12.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.3.tgz", - "integrity": "sha512-opgSsy+cEF9N8MgaVPnWVtdJ3o4mV2aMHvDq7thkQUFt0EuOHJon4rQpJfhjmNHB+ikl0Cd6WhWIErOyQ+f7tw==" - } + "@types/node": ">= 8" } }, "@samverschueren/stream-to-observable": { @@ -3201,9 +3117,9 @@ "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, "@types/cheerio": { - "version": "0.22.13", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.13.tgz", - "integrity": "sha512-OZd7dCUOUkiTorf97vJKwZnSja/DmHfuBAroe1kREZZTCf/tlFecwHhsOos3uVHxeKGZDwzolIrCUApClkdLuA==", + "version": "0.22.14", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.14.tgz", + "integrity": "sha512-SVtcP2fvPYrebTwpyqxjxb7K5v3ZOAdH409yAEWFPpZThCSGa1K2IFfx6Rg6ttvThCBQXP4fU9WF94sqLoiQGg==", "requires": { "@types/node": "*" } @@ -3346,9 +3262,9 @@ } }, "@types/react-dom": { - "version": "16.9.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.3.tgz", - "integrity": "sha512-FUuZKXPr9qlzUT9lhuzrZgLjH63TvNn28Ch3MvKG4B+F52zQtO8DtE0Opbncy3xaucNZM2WIPfuNTgkbKx5Brg==", + "version": "16.9.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.4.tgz", + "integrity": "sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw==", "requires": { "@types/react": "*" } @@ -3365,9 +3281,9 @@ } }, "@types/restify": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@types/restify/-/restify-5.0.11.tgz", - "integrity": "sha512-UQposjIQewSD4c4gvvW/3kyhAX4RF/rIcoivFYRrRF4km9phHK6PaiST+Ueau5Lq/4b3XYt6iGgzwTxn645PQw==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/restify/-/restify-8.4.1.tgz", + "integrity": "sha512-atNjC2l5tNwWmYit348Sba5aDabg8aMfIVSkzPP4/svq5tyF1obbfL3NUJntTEnzq1ttTxwiGWVzybTu8MZdjw==", "requires": { "@types/bunyan": "*", "@types/node": "*", @@ -3421,12 +3337,11 @@ } }, "@types/vfile-message": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-1.0.1.tgz", - "integrity": "sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-2.0.0.tgz", + "integrity": "sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==", "requires": { - "@types/node": "*", - "@types/unist": "*" + "vfile-message": "*" } }, "@types/ws": { @@ -3942,11 +3857,6 @@ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" }, - "ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" - }, "any-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", @@ -5300,10 +5210,37 @@ "ms": "2.0.0" } }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, @@ -5343,9 +5280,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.2.tgz", - "integrity": "sha512-sAh60KDol+MpwOr1RTK0+HgBEYejKsxdpmrOS1Wts5bI03dLzq8F7T0sRXDKeaEK8iWDlGfdzxrzg6vx/c5pNA==" + "version": "10.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz", + "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==" }, "fs-extra": { "version": "7.0.1", @@ -5422,9 +5359,9 @@ } }, "@types/node": { - "version": "10.17.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.2.tgz", - "integrity": "sha512-sAh60KDol+MpwOr1RTK0+HgBEYejKsxdpmrOS1Wts5bI03dLzq8F7T0sRXDKeaEK8iWDlGfdzxrzg6vx/c5pNA==" + "version": "10.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz", + "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==" }, "jsonwebtoken": { "version": "8.0.1", @@ -5484,9 +5421,9 @@ }, "dependencies": { "core-js": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.6.tgz", - "integrity": "sha512-u4oM8SHwmDuh5mWZdDg9UwNVq5s1uqq6ZDLLIs07VY+VJU91i3h4f3K/pgFvtUQPGdeStrZ+odKyfyt4EnKHfA==" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.1.tgz", + "integrity": "sha512-KX/dnuY/J8FtEwbnrzmAjUYgLqtk+cxM86hfG60LGiW3MmltIc2yAmDgBgEkfm0blZhUrdr1Zd84J2Y14mLxzg==" } } }, @@ -5516,9 +5453,9 @@ }, "dependencies": { "react-redux": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.1.1.tgz", - "integrity": "sha512-QsW0vcmVVdNQzEkrgzh2W3Ksvr8cqpAv5FhEk7tNEft+5pp7rXxAudTz3VOPawRkLIepItpkEIyLcN/VVXzjTg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.1.3.tgz", + "integrity": "sha512-uI1wca+ECG9RoVkWQFF4jDMqmaw0/qnvaSvOoL/GA4dNxf6LoV8sUAcNDvE5NWKs4hFpn0t6wswNQnY3f7HT3w==", "requires": { "@babel/runtime": "^7.5.5", "hoist-non-react-statics": "^3.3.0", @@ -6041,9 +5978,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001006", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001006.tgz", - "integrity": "sha512-MXnUVX27aGs/QINz+QG1sWSLDr3P1A3Hq5EUWoIt0T7K24DuvMxZEnh3Y5aHlJW6Bz2aApJdSewdYLd8zQnUuw==" + "version": "1.0.30001008", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001008.tgz", + "integrity": "sha512-b8DJyb+VVXZGRgJUa30cbk8gKHZ3LOZTBLaUEEVr2P4xpmFigOCc62CO4uzquW641Ouq1Rm9N+rWLWdSYDaDIw==" }, "capture-exit": { "version": "2.0.0", @@ -6058,15 +5995,6 @@ "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" }, - "cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", - "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - } - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -6350,21 +6278,6 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==" }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - } - } - }, "cli-table3": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", @@ -6422,15 +6335,6 @@ } } }, - "cli-usage": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.10.tgz", - "integrity": "sha512-Q/s1S4Jz5LYI0LQ+XiFQCXkhMzn244ddyIffni8JIq/kL95DvQomVQ0cJC41c76hH9/FmZGY7rZB53y/bXHtRA==", - "requires": { - "marked": "^0.7.0", - "marked-terminal": "^3.3.0" - } - }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -6490,18 +6394,9 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "clone-regexp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.1.tgz", - "integrity": "sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw==", - "requires": { - "is-regexp": "^1.0.0", - "is-supported-regexp-flag": "^1.0.0" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, "clone-response": { @@ -6618,9 +6513,9 @@ } }, "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" }, "common-tags": { "version": "1.8.0", @@ -6751,11 +6646,6 @@ "tree-kill": "^1.1.0" }, "dependencies": { - "commander": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" - }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", @@ -6856,9 +6746,9 @@ } }, "conventional-changelog-angular": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.5.tgz", - "integrity": "sha512-RrkdWnL/TVyWV1ayWmSsrWorsTDqjL/VwG5ZSEneBQrd65ONcfeA1cW7FLtNweQyMiKOyriCMTKRSlk18DjTrw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", "requires": { "compare-func": "^1.3.1", "q": "^1.5.1" @@ -6942,21 +6832,21 @@ } }, "conventional-changelog-preset-loader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.2.0.tgz", - "integrity": "sha512-zXB+5vF7D5Y3Cb/rJfSyCCvFphCVmF8mFqOdncX3BmjZwAtGAPfYrBcT225udilCKvBbHgyzgxqz2GWDB5xShQ==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz", + "integrity": "sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ==" }, "conventional-changelog-writer": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.9.tgz", - "integrity": "sha512-2Y3QfiAM37WvDMjkVNaRtZgxVzWKj73HE61YQ/95T53yle+CRwTVSl6Gbv/lWVKXeZcM5af9n9TDVf0k7Xh+cw==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.10.tgz", + "integrity": "sha512-vtO9vBAVh7XnSpGLTB1BOGgsGTz1MdvFjzbSXLrtapWCHWwuVOZFgwdLhlS0MaXwlF1dksWdEb6tnr42Ie2INw==", "requires": { "compare-func": "^1.3.1", "conventional-commits-filter": "^2.0.2", "dateformat": "^3.0.0", "handlebars": "^4.4.0", "json-stringify-safe": "^5.0.1", - "lodash": "^4.2.1", + "lodash": "^4.17.15", "meow": "^4.0.0", "semver": "^6.0.0", "split": "^1.0.0", @@ -7095,13 +6985,13 @@ } }, "conventional-commits-parser": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.5.tgz", - "integrity": "sha512-qVz9+5JwdJzsbt7JbJ6P7NOXBGt8CyLFJYSjKAuPSgO+5UGfcsbk9EMR+lI8Unlvx6qwIc2YDJlrGIfay2ehNA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.7.tgz", + "integrity": "sha512-4mx/FRC92z0yIiXGyRVYQFhn0jWDwvxnj2UuLaUi3hJSG4Thall6GXA8YOPHQK2qvotciJandJIVmuSvLgDLbQ==", "requires": { "JSONStream": "^1.0.4", - "is-text-path": "^2.0.0", - "lodash": "^4.2.1", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", "meow": "^4.0.0", "split2": "^2.0.0", "through2": "^3.0.0", @@ -7371,9 +7261,9 @@ } }, "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "requires": { "safe-buffer": "~5.1.1" } @@ -7498,9 +7388,9 @@ "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" }, "core-js-compat": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.3.6.tgz", - "integrity": "sha512-YnwZG/+0/f7Pf6Lr3jxtVAFjtGBW9lsLYcqrxhYJai1GfvrP8DEyEpnNzj/FRQfIkOOfk1j5tTBvPBLWVVJm4A==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.1.tgz", + "integrity": "sha512-YdeJI26gLc0CQJ9asLE5obEgBz2I0+CIgnoTbS2T0d5IPQw/OCgCIFR527RmpduxjrB3gSEHoGOCTq9sigOyfw==", "dev": true, "requires": { "browserslist": "^4.7.2", @@ -7853,34 +7743,34 @@ "integrity": "sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ==" }, "csv": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/csv/-/csv-1.2.1.tgz", - "integrity": "sha1-UjHt/BxxUlEuxFeBB2p6l/9SXAw=", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.1.3.tgz", + "integrity": "sha512-uHPF5nxxFgcBQ/Mkicjh+IcQJeooIcN8gS/5mnvIdIccLh3Qf792jXE00ovdYDmABhE0yTMNCZgx3ZsBrR2GoQ==", "requires": { - "csv-generate": "^1.1.2", - "csv-parse": "^1.3.3", - "csv-stringify": "^1.1.2", - "stream-transform": "^0.2.2" + "csv-generate": "^3.2.3", + "csv-parse": "^4.4.6", + "csv-stringify": "^5.3.3", + "stream-transform": "^2.0.1" } }, "csv-generate": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-1.1.2.tgz", - "integrity": "sha1-7GsA7a7W5ZrZwgWC9MNk4osUYkA=" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.3.tgz", + "integrity": "sha512-IcR3K0Nx+nJAkcU2eAglVR7DuHnxcuhUM2w2cR+aHOW7bZp2S5LyN2HF3zTkp6BV/DjR6ykoKznUm+AjnWcOKg==" }, "csv-parse": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.3.3.tgz", - "integrity": "sha1-0c/YdDwvhJoKuy/VRNtWaV0ZpJA=" - }, - "csv-stringify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-1.1.2.tgz", - "integrity": "sha1-d6QVJlgbzjOA8SsA18W7rHDIK1g=", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.6.5.tgz", + "integrity": "sha512-tUohmlM5X1Wtn7aRA4FsJMmnvGo+GUknK/Dp+//ms7pvpXADda5HIi5vFYOvAs/WSn5JUM1bt2AT3TxtDFV3Cw==", "requires": { - "lodash.get": "~4.4.2" + "pad": "^3.2.0" } }, + "csv-stringify": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.3.3.tgz", + "integrity": "sha512-q8Qj+/lN74LRmG7Mg0LauE5WcnJOD5MEGe1gI57IYJCB61KWuEbAFHm1uIPDkI26aqElyBB57SlE2GGwq2EY5A==" + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -7942,24 +7832,12 @@ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" }, - "debounce": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", - "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==" - }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } + "ms": "2.0.0" } }, "debuglog": { @@ -8177,9 +8055,9 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -8340,9 +8218,9 @@ } }, "dom-serializer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz", - "integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "requires": { "domelementtype": "^2.0.1", "entities": "^2.0.0" @@ -8448,40 +8326,6 @@ "stream-shift": "^1.0.0" } }, - "dynamic-dedupe": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.2.0.tgz", - "integrity": "sha1-UPfChoSDHs8cFwqrZ6HVMRzdds4=", - "requires": { - "xtend": "~2.0.6" - }, - "dependencies": { - "is-object": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-0.1.2.tgz", - "integrity": "sha1-AO+8CIFsM8/ErIJR0TLhDcZQmNc=" - }, - "object-keys": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.2.0.tgz", - "integrity": "sha1-zd7AKZiwkb5CvxA1rjLknxy26mc=", - "requires": { - "foreach": "~2.0.1", - "indexof": "~0.0.1", - "is": "~0.2.6" - } - }, - "xtend": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.0.6.tgz", - "integrity": "sha1-XqZXptukRwacLlnFihE4ywxebO4=", - "requires": { - "is-object": "~0.1.2", - "object-keys": "~0.2.0" - } - } - } - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -8520,9 +8364,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.2.tgz", - "integrity": "sha512-sAh60KDol+MpwOr1RTK0+HgBEYejKsxdpmrOS1Wts5bI03dLzq8F7T0sRXDKeaEK8iWDlGfdzxrzg6vx/c5pNA==" + "version": "10.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz", + "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==" } } }, @@ -8927,9 +8771,9 @@ } }, "electron-to-chromium": { - "version": "1.3.296", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.296.tgz", - "integrity": "sha512-s5hv+TSJSVRsxH190De66YHb50pBGTweT9XGWYu/LMR20KX6TsjFzObo36CjVAzM+PUeeKSBRtm/mISlCzeojQ==" + "version": "1.3.306", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz", + "integrity": "sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A==" }, "electron-updater": { "version": "3.0.3", @@ -9172,9 +9016,9 @@ } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -9732,10 +9576,18 @@ "safe-buffer": "^5.1.1" } }, + "ewma": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", + "integrity": "sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw==", + "requires": { + "assert-plus": "^1.0.0" + } + }, "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==" + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==" }, "execa": { "version": "0.7.0", @@ -9940,6 +9792,23 @@ "ms": "2.0.0" } }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -9949,6 +9818,43 @@ "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, @@ -10048,6 +9954,11 @@ "time-stamp": "^1.0.0" } }, + "fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -10181,14 +10092,6 @@ "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz", "integrity": "sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g==" }, - "filewatcher": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/filewatcher/-/filewatcher-3.0.1.tgz", - "integrity": "sha1-9KGVc1Xdr0Q8zXiolfPVXiPIoDQ=", - "requires": { - "debounce": "^1.0.0" - } - }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -10231,6 +10134,11 @@ "requires": { "ms": "2.0.0" } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, @@ -10244,6 +10152,16 @@ "pkg-dir": "^3.0.0" } }, + "find-my-way": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.1.tgz", + "integrity": "sha512-pzZA9/PlhDGG5PRzmd4vH4AbKW7FO68RE7q2I3NzjJHcVPukYbDA7bPdArg7ySKfS6pKki+qhrawFoN6aNZfjA==", + "requires": { + "fast-decode-uri-component": "^1.0.0", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + }, "find-replace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", @@ -10322,16 +10240,6 @@ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } } }, "for-in": { @@ -10339,11 +10247,6 @@ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -11026,9 +10929,9 @@ } }, "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", + "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==" }, "get-stdin": { "version": "4.0.1", @@ -11356,9 +11259,9 @@ } }, "glob": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", - "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11549,9 +11452,9 @@ } }, "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" }, "handlebars": { "version": "4.5.1", @@ -11821,15 +11724,14 @@ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" }, "dependencies": { "inherits": { @@ -11868,16 +11770,6 @@ "requires": { "agent-base": "4", "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } } }, "http-proxy-middleware": { @@ -12138,11 +12030,6 @@ "repeating": "^2.0.0" } }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -12324,11 +12211,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" }, - "is": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/is/-/is-0.2.7.tgz", - "integrity": "sha1-OzSixI81mXLzUEKEkZOucmS2NWI=" - }, "is-absolute-url": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", @@ -12603,7 +12485,8 @@ "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true }, "is-resolvable": { "version": "1.1.0", @@ -12643,11 +12526,6 @@ "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=" }, - "is-supported-regexp-flag": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz", - "integrity": "sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ==" - }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -12657,11 +12535,11 @@ } }, "is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "requires": { - "text-extensions": "^2.0.0" + "text-extensions": "^1.0.0" } }, "is-typedarray": { @@ -13846,25 +13724,25 @@ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" }, "lerna": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.18.3.tgz", - "integrity": "sha512-Bnr/RjyDSVA2Vu+NArK7do4UIpyy+EShOON7tignfAekPbi7cNDnMMGgSmbCQdKITkqPACMfCMdyq0hJlg6n3g==", - "requires": { - "@lerna/add": "3.18.0", - "@lerna/bootstrap": "3.18.0", - "@lerna/changed": "3.18.3", - "@lerna/clean": "3.18.0", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.18.4.tgz", + "integrity": "sha512-DiU53cvMxaU07Bj2HwBwUQ2O3c/ORNq/QwKj1vGJH4vSkZSTUxPryp2baSNlt8PmnLNXOVpw0vOTRkEF+6n/cA==", + "requires": { + "@lerna/add": "3.18.4", + "@lerna/bootstrap": "3.18.4", + "@lerna/changed": "3.18.4", + "@lerna/clean": "3.18.4", "@lerna/cli": "3.18.0", "@lerna/create": "3.18.0", "@lerna/diff": "3.18.0", - "@lerna/exec": "3.18.0", + "@lerna/exec": "3.18.4", "@lerna/import": "3.18.0", "@lerna/init": "3.18.0", "@lerna/link": "3.18.0", - "@lerna/list": "3.18.0", - "@lerna/publish": "3.18.3", - "@lerna/run": "3.18.0", - "@lerna/version": "3.18.3", + "@lerna/list": "3.18.4", + "@lerna/publish": "3.18.4", + "@lerna/run": "3.18.4", + "@lerna/version": "3.18.4", "import-local": "^2.0.0", "npmlog": "^4.1.2" } @@ -13933,6 +13811,12 @@ "yup": "^0.27.0" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -14152,11 +14036,6 @@ "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=" }, - "lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=" - }, "lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", @@ -14166,29 +14045,11 @@ "lodash.keys": "^3.0.0" } }, - "lodash._baseclone": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", - "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", - "requires": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._baseassign": "^3.0.0", - "lodash._basefor": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" }, - "lodash._basefor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=" - }, "lodash._baseisequal": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz", @@ -14489,9 +14350,9 @@ } }, "loglevel": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", - "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==" + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", + "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==" }, "loglevel-colored-level-prefix": { "version": "1.0.0", @@ -14811,24 +14672,6 @@ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==" }, - "marked": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==" - }, - "marked-terminal": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.3.0.tgz", - "integrity": "sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A==", - "requires": { - "ansi-escapes": "^3.1.0", - "cardinal": "^2.1.1", - "chalk": "^2.4.1", - "cli-table": "^0.3.1", - "node-emoji": "^1.4.1", - "supports-hyperlinks": "^1.0.1" - } - }, "matcher": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", @@ -14871,9 +14714,9 @@ } }, "mdast-util-compact": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz", - "integrity": "sha512-nRiU5GpNy62rZppDKbLwhhtw5DXoFMqw9UNZFmlPsNaQCZ//WLjGKUwWMdJrUH+Se7UvtO2gXtAMe0g/N+eI5w==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", + "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==", "requires": { "unist-util-visit": "^1.1.0" } @@ -15076,16 +14919,16 @@ "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==" }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "requires": { - "mime-db": "1.40.0" + "mime-db": "1.42.0" } }, "mimic-fn": { @@ -15220,6 +15063,11 @@ } } }, + "mixme": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.3.2.tgz", + "integrity": "sha512-tilCZOvIhRETXJuTmxxpz8mgplF7gmFhcH05JuR/YL+JLO98gLRQ1Mk4XpYQxxbPMKupSOv+Bidw7EKv8wds1w==" + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -15410,6 +15258,13 @@ "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } } }, "negotiator": { @@ -15443,68 +15298,6 @@ "semver": "^5.4.1" } }, - "node-dev": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-3.1.3.tgz", - "integrity": "sha1-WCcZIj69711jBZ5qf7zSOZ/A+E0=", - "requires": { - "dateformat": "~1.0.4-1.2.3", - "dynamic-dedupe": "^0.2.0", - "filewatcher": "~3.0.0", - "minimist": "^1.1.3", - "node-notifier": "^4.0.2", - "resolve": "^1.0.0" - }, - "dependencies": { - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } - }, - "lodash.clonedeep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", - "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", - "requires": { - "lodash._baseclone": "^3.0.0", - "lodash._bindcallback": "^3.0.0" - } - }, - "node-notifier": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.1.tgz", - "integrity": "sha1-BW0UJE89zBzq3+aK+c/wxUc6M/M=", - "requires": { - "cli-usage": "^0.1.1", - "growly": "^1.2.0", - "lodash.clonedeep": "^3.0.0", - "minimist": "^1.1.1", - "semver": "^5.1.0", - "shellwords": "^0.1.0", - "which": "^1.0.5" - } - } - } - }, - "node-emoji": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", - "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", - "requires": { - "lodash.toarray": "^4.4.0" - }, - "dependencies": { - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" - } - } - }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", @@ -15586,9 +15379,9 @@ }, "dependencies": { "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -15959,6 +15752,14 @@ "commander": "^2.9.0", "npm-path": "^2.0.2", "which": "^1.2.10" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } } }, "npmlog": { @@ -16010,9 +15811,9 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" }, "oauth-sign": { "version": "0.9.0", @@ -16091,9 +15892,9 @@ } }, "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-is": { "version": "1.0.1", @@ -16244,25 +16045,20 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" } } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "ora": { @@ -16377,17 +16173,6 @@ "os-tmpdir": "^1.0.0" } }, - "output-file-sync": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", - "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "is-plain-obj": "^1.1.0", - "mkdirp": "^0.5.1" - } - }, "p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", @@ -16541,6 +16326,14 @@ } } }, + "pad": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pad/-/pad-3.2.0.tgz", + "integrity": "sha512-2u0TrjcGbOjBTJpyewEl4hBO3OeX5wWue7eIFPzQTg6wFSvoaHcBTTUY5m+n0hd04gmTCPuY0kCpVIVuw5etwg==", + "requires": { + "wcwidth": "^1.0.1" + } + }, "pako": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", @@ -16731,9 +16524,9 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "requires": { "isarray": "0.0.1" }, @@ -16792,6 +16585,14 @@ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==" }, + "pidusage": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.17.tgz", + "integrity": "sha512-N8X5v18rBmlBoArfS83vrnD0gIFyZkXEo7a5pAS2aT0i2OLVymFb2AzVg+v8l/QcXnE1JwZcaXR8daJcoJqtjw==", + "requires": { + "safe-buffer": "^5.1.2" + } + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -16869,6 +16670,21 @@ "async": "^2.6.2", "debug": "^3.1.1", "mkdirp": "^0.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "posix-character-classes": { @@ -17043,9 +16859,9 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==" + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, "prettier-eslint": { "version": "8.8.2", @@ -17979,9 +17795,9 @@ } }, "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", + "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.3" @@ -18262,6 +18078,35 @@ "http-errors": "1.7.2", "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "dependencies": { + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } } }, "rc": { @@ -18542,9 +18387,9 @@ } }, "react-hot-loader": { - "version": "4.12.15", - "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.15.tgz", - "integrity": "sha512-sgkN6g+tgPE6xZzD0Ysqll7KUFYJbMX0DrczT5OxD6S7hZlSnmqSC3ceudwCkiDd65ZTtm+Ayk4Y9k5xxCvpOw==", + "version": "4.12.17", + "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.17.tgz", + "integrity": "sha512-nee5q4Xip6+wD8DrCWxVUH0zT488K1zRG1KezJTb8oEbRO1JZvnEizbOG7BwnRfxxjk5QSyx6fPXeBf2fToBhw==", "requires": { "fast-levenshtein": "^2.0.6", "global": "^4.3.0", @@ -18681,9 +18526,9 @@ } }, "read-cmd-shim": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.4.tgz", - "integrity": "sha512-Pqpl3qJ/QdOIjRYA0q5DND/gLvGOfpIz/fYVDGYpOXfW/lFrIttmLsBnd6IkyK10+JHU9zhsaudfvrQTBB9YFQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", + "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", "requires": { "graceful-fs": "^4.1.2" } @@ -18927,14 +18772,6 @@ "strip-indent": "^1.0.1" } }, - "redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "requires": { - "esprima": "~4.0.0" - } - }, "redux": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", @@ -19201,30 +19038,30 @@ } }, "request-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", - "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", + "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", "requires": { "bluebird": "^3.5.0", - "request-promise-core": "1.1.2", + "request-promise-core": "1.1.3", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" } }, "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.15" } }, "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", "requires": { - "request-promise-core": "1.1.2", + "request-promise-core": "1.1.3", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" } @@ -19367,36 +19204,56 @@ } }, "restify": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/restify/-/restify-5.2.1.tgz", - "integrity": "sha512-OZbqEvRm04Px+vXm3d31sI58HjN2qRaY6O6tA9LGRgyLZJ5+oW4qaLCdKddXfUX6MjtwAc+LLkDQmDbYUifLXA==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/restify/-/restify-8.3.3.tgz", + "integrity": "sha512-E1xYBmC1gD3IUAeDhZx7VdmD69SSz8Ti5b69nwBgWCpTPIi3XImucPNnAtSEz5fHUW2F/arwSDUe1TPqt+5/zQ==", "requires": { "assert-plus": "^1.0.0", - "bunyan": "^1.8.1", - "clone-regexp": "^1.0.0", - "csv": "^1.1.0", + "bunyan": "^1.8.12", + "csv": "^5.1.1", "dtrace-provider": "^0.8.1", "escape-regexp-component": "^1.0.2", - "formidable": "^1.0.17", - "http-signature": "^1.0.0", - "lodash": "^4.17.4", - "lru-cache": "^4.0.1", - "mime": "^1.2.11", - "negotiator": "^0.6.1", - "once": "^1.3.0", - "qs": "^6.2.1", - "restify-errors": "^4.2.3", - "semver": "^5.0.1", - "spdy": "^3.3.3", - "uuid": "^3.0.0", - "vasync": "^1.6.4", - "verror": "^1.9.0" + "ewma": "^2.0.1", + "find-my-way": "^2.0.1", + "formidable": "^1.2.1", + "http-signature": "^1.2.0", + "lodash": "^4.17.11", + "lru-cache": "^5.1.1", + "mime": "^2.4.3", + "negotiator": "^0.6.2", + "once": "^1.4.0", + "pidusage": "^2.0.17", + "qs": "^6.7.0", + "restify-errors": "^8.0.0", + "semver": "^6.1.1", + "send": "^0.16.2", + "spdy": "^4.0.0", + "uuid": "^3.3.2", + "vasync": "^2.2.0" }, "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } }, @@ -19409,14 +19266,14 @@ } }, "restify-errors": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-4.3.0.tgz", - "integrity": "sha1-7JDzCTTX8xGRNRgd/DA+ML5gGr4=", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-8.0.1.tgz", + "integrity": "sha512-EFQpxS828J0SBTNuJjh+rHD0OE8BoqnaxMAzuKHRNnGt5BV/212HHQIelZG4zjZYpTDEiuVAhQYHwSGSzAz0Ag==", "requires": { + "@netflix/nerror": "^1.0.0", "assert-plus": "^1.0.0", - "lodash": "^4.2.1", - "safe-json-stringify": "^1.0.3", - "verror": "^1.8.1" + "lodash": "^4.17.15", + "safe-json-stringify": "^1.0.4" } }, "restore-cursor": { @@ -19567,6 +19424,21 @@ "ret": "~0.1.10" } }, + "safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "requires": { + "ret": "~0.2.0" + }, + "dependencies": { + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" + } + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -19825,10 +19697,15 @@ "semver": "^5.0.3" } }, + "semver-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", + "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" + }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -19837,12 +19714,12 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "debug": { @@ -19851,24 +19728,12 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } }, "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" } } }, @@ -19898,27 +19763,6 @@ "requires": { "ms": "2.0.0" } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" } } }, @@ -19931,6 +19775,75 @@ "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.17.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } } }, "set-blocking": { @@ -19965,9 +19878,9 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, "sha.js": { "version": "2.4.11", @@ -20084,9 +19997,9 @@ } }, "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", + "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==" }, "slash": { "version": "1.0.0", @@ -20116,9 +20029,9 @@ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, "smart-buffer": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", - "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" }, "snapdragon": { "version": "0.8.2", @@ -20293,12 +20206,12 @@ } }, "socks": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", - "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", "requires": { - "ip": "^1.1.5", - "smart-buffer": "4.0.2" + "ip": "1.1.5", + "smart-buffer": "^4.1.0" } }, "socks-proxy-agent": { @@ -20433,48 +20346,66 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" }, "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", "requires": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", + "debug": "^4.1.0", + "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" + "spdy-transport": "^3.0.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, "spdy-transport": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.1.tgz", - "integrity": "sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "requires": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", + "debug": "^4.1.0", + "detect-node": "^2.0.4", "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } @@ -20660,9 +20591,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, "stdout-stream": { "version": "1.4.1", @@ -20713,9 +20644,12 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, "stream-transform": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.2.2.tgz", - "integrity": "sha1-dYZ0h/SVKPi/HYJJllh1PQLfeDg=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.1.tgz", + "integrity": "sha512-GiTcO/rRvZP2R8WPwxmxCFP+Of1yIATuFAmYkvSLDfcD93X2WHiPwdgIqeFT2CvL1gyAsjQvu1nB6RDNQ5b2jw==", + "requires": { + "mixme": "^0.3.1" + } }, "strict-uri-encode": { "version": "1.1.0", @@ -20919,22 +20853,6 @@ "has-flag": "^3.0.0" } }, - "supports-hyperlinks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", - "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", - "requires": { - "has-flag": "^2.0.0", - "supports-color": "^5.0.0" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - } - } - }, "symbol-observable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", @@ -21117,15 +21035,20 @@ } }, "terser": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.9.tgz", - "integrity": "sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.0.tgz", + "integrity": "sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", "source-map-support": "~0.5.12" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -21263,9 +21186,9 @@ } }, "text-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz", - "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==" }, "text-table": { "version": "0.2.0", @@ -21667,14 +21590,19 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.5.tgz", - "integrity": "sha512-7L3W+Npia1OCr5Blp4/Vw83tK1mu5gnoIURtT1fUVfQ3Kf8WStWV6NJz0fdoBJZls0KlweruRTLVe6XLafmy5g==", + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.8.tgz", + "integrity": "sha512-XhHJ3S3ZyMwP8kY1Gkugqx3CJh2C3O0y8NPiSxtm1tyD/pktLAkFZsFGpuNfTZddKDQ/bbDBLAd2YyA1pbi8HQ==", "requires": { "commander": "~2.20.3", "source-map": "~0.6.1" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -21910,17 +21838,20 @@ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==" }, "unist-util-remove-position": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz", - "integrity": "sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", + "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", "requires": { "unist-util-visit": "^1.1.0" } }, "unist-util-stringify-position": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", - "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.2.tgz", + "integrity": "sha512-nK5n8OGhZ7ZgUwoUbL8uiVRwAbZyzBsB/Ddrlbu6jwwubFza4oe15KlyEaLNMXQW1svOQq4xesUeqA85YrIUQA==", + "requires": { + "@types/unist": "^2.0.2" + } }, "unist-util-visit": { "version": "1.4.1", @@ -22257,26 +22188,11 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "vasync": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.4.tgz", - "integrity": "sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.0.tgz", + "integrity": "sha1-z951GGChWCLbOxMrxZsRakra8Bs=", "requires": { - "verror": "1.6.0" - }, - "dependencies": { - "extsprintf": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", - "integrity": "sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=" - }, - "verror": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", - "integrity": "sha1-fROyex+swuLakEBetepuW90lLqU=", - "requires": { - "extsprintf": "1.2.0" - } - } + "verror": "1.10.0" } }, "verror": { @@ -22298,19 +22214,35 @@ "replace-ext": "1.0.0", "unist-util-stringify-position": "^1.0.0", "vfile-message": "^1.0.0" + }, + "dependencies": { + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==" + }, + "vfile-message": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", + "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "requires": { + "unist-util-stringify-position": "^1.1.1" + } + } } }, "vfile-location": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.5.tgz", - "integrity": "sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", + "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==" }, "vfile-message": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", - "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.2.tgz", + "integrity": "sha512-gNV2Y2fDvDOOqq8bEe7cF3DXU6QgV4uA9zMR2P8tix11l1r7zju3zry3wZ8sx+BEfuO6WQ7z2QzfWTvqHQiwsA==", "requires": { - "unist-util-stringify-position": "^1.1.1" + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" } }, "vinyl": { @@ -22352,9 +22284,9 @@ } }, "vm-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", - "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, "vue-eslint-parser": { "version": "2.0.3", @@ -22899,11 +22831,6 @@ } } }, - "handle-thing": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", - "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -22943,16 +22870,6 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -22991,31 +22908,6 @@ } } }, - "spdy": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", - "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -23220,10 +23112,15 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" }, "worker-farm": { "version": "1.7.0", diff --git a/packages/app/client/package.json b/packages/app/client/package.json index bfb7b29f2..6447773d1 100644 --- a/packages/app/client/package.json +++ b/packages/app/client/package.json @@ -98,7 +98,6 @@ "dependencies": { "@babel/runtime": "^7.1.5", "@bfemulator/app-shared": "^1.0.0", - "@bfemulator/emulator-core": "1.0.0-0", "@bfemulator/sdk-client": "^1.0.0", "@bfemulator/sdk-shared": "^1.0.0", "@bfemulator/ui-react": "^1.0.0", diff --git a/packages/app/client/src/state/actions/windowStateActions.spec.ts b/packages/app/client/src/state/actions/windowStateActions.spec.ts index 2b0af51ee..2c1320598 100644 --- a/packages/app/client/src/state/actions/windowStateActions.spec.ts +++ b/packages/app/client/src/state/actions/windowStateActions.spec.ts @@ -66,7 +66,10 @@ describe('Window state actions', () => { }); test('setAvailableThemes action', () => { - const themes = [{ name: 'light', href: './light.css' }, { name: 'dark', href: './dark.css' }]; + const themes = [ + { name: 'light', href: './light.css' }, + { name: 'dark', href: './dark.css' }, + ]; expect(windowStateActions.setAvailableThemes(themes)).toEqual({ type: windowStateActions.SET_AVAILABLE_THEMES, payload: { availableThemes: themes }, diff --git a/packages/app/client/src/state/reducers/users.spec.ts b/packages/app/client/src/state/reducers/users.spec.ts index 7a32ac4f6..18de8a282 100644 --- a/packages/app/client/src/state/reducers/users.spec.ts +++ b/packages/app/client/src/state/reducers/users.spec.ts @@ -54,7 +54,11 @@ describe('users reducer', () => { user1: {}, }, }; - const action = addUsers([{ name: '', id: 'user1' }, { name: '', id: 'user2' }, { name: '', id: 'user3' }]); + const action = addUsers([ + { name: '', id: 'user1' }, + { name: '', id: 'user2' }, + { name: '', id: 'user3' }, + ]); const state = users(initialState, action); expect(state).toEqual({ diff --git a/packages/app/client/src/state/reducers/windowState.spec.ts b/packages/app/client/src/state/reducers/windowState.spec.ts index 34cc95cf6..031696b73 100644 --- a/packages/app/client/src/state/reducers/windowState.spec.ts +++ b/packages/app/client/src/state/reducers/windowState.spec.ts @@ -65,7 +65,10 @@ describe('windowState reducer', () => { }); it('should handle a set available themes action', () => { - const themes = [{ name: 'light', href: './light.css' }, { name: 'dark', href: './dark.css' }]; + const themes = [ + { name: 'light', href: './light.css' }, + { name: 'dark', href: './dark.css' }, + ]; const action = setAvailableThemes(themes); const state = windowState({} as any, action); diff --git a/packages/app/client/src/state/sagas/resourcesSagas.ts b/packages/app/client/src/state/sagas/resourcesSagas.ts index 8ea5783f5..03be6dc32 100644 --- a/packages/app/client/src/state/sagas/resourcesSagas.ts +++ b/packages/app/client/src/state/sagas/resourcesSagas.ts @@ -53,7 +53,11 @@ export class ResourcesSagas { private static commandService: CommandServiceImpl; public static *openContextMenuForResource(action: ResourcesAction): IterableIterator { - const menuItems = [{ label: 'Open file location', id: 0 }, { label: 'Rename', id: 1 }, { label: 'Delete', id: 2 }]; + const menuItems = [ + { label: 'Open file location', id: 0 }, + { label: 'Rename', id: 1 }, + { label: 'Delete', id: 2 }, + ]; const result = yield ResourcesSagas.commandService.remoteCall( SharedConstants.Commands.Electron.DisplayContextMenu, diff --git a/packages/app/client/src/ui/dialogs/azureLoginPromptDialog/azureLoginPromptDialogContainer.ts b/packages/app/client/src/ui/dialogs/azureLoginPromptDialog/azureLoginPromptDialogContainer.ts index 76786f0f1..074305ad6 100644 --- a/packages/app/client/src/ui/dialogs/azureLoginPromptDialog/azureLoginPromptDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/azureLoginPromptDialog/azureLoginPromptDialogContainer.ts @@ -50,7 +50,4 @@ const mapDispatchToProps = (_dispatch: () => void): AzureLoginPromptDialogProps }; }; -export const AzureLoginPromptDialogContainer = connect( - null, - mapDispatchToProps -)(AzureLoginPromptDialog as any) as any; +export const AzureLoginPromptDialogContainer = connect(null, mapDispatchToProps)(AzureLoginPromptDialog as any) as any; diff --git a/packages/app/client/src/ui/dialogs/botCreationDialog/botCreationDialogContainer.ts b/packages/app/client/src/ui/dialogs/botCreationDialog/botCreationDialogContainer.ts index 7e07a6339..0caf1ae02 100644 --- a/packages/app/client/src/ui/dialogs/botCreationDialog/botCreationDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/botCreationDialog/botCreationDialogContainer.ts @@ -45,7 +45,4 @@ const mapDispatchToProps = (_dispatch): BotCreationDialogProps => { }; }; -export const BotCreationDialogContainer = connect( - undefined, - mapDispatchToProps -)(BotCreationDialog); +export const BotCreationDialogContainer = connect(undefined, mapDispatchToProps)(BotCreationDialog); diff --git a/packages/app/client/src/ui/dialogs/botSettingsEditor/botSettingsEditorContainer.ts b/packages/app/client/src/ui/dialogs/botSettingsEditor/botSettingsEditorContainer.ts index df6d3b5ed..3f1262c83 100644 --- a/packages/app/client/src/ui/dialogs/botSettingsEditor/botSettingsEditorContainer.ts +++ b/packages/app/client/src/ui/dialogs/botSettingsEditor/botSettingsEditorContainer.ts @@ -57,7 +57,4 @@ const mapDispatchToProps = dispatch => ({ sendNotification: notification => dispatch(beginAdd(notification)), }); -export const BotSettingsEditorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(BotSettingsEditor); +export const BotSettingsEditorContainer = connect(mapStateToProps, mapDispatchToProps)(BotSettingsEditor); diff --git a/packages/app/client/src/ui/dialogs/connectServicePromptDialog/connectServicePromptDialogContainer.ts b/packages/app/client/src/ui/dialogs/connectServicePromptDialog/connectServicePromptDialogContainer.ts index 22fcc4d66..ab232319d 100644 --- a/packages/app/client/src/ui/dialogs/connectServicePromptDialog/connectServicePromptDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/connectServicePromptDialog/connectServicePromptDialogContainer.ts @@ -56,7 +56,4 @@ const mapDispatchToProps = dispatch => ( }; }; -export const ConnectServicePromptDialogContainer = connect( - null, - mapDispatchToProps -)(ConnectServicePromptDialog); +export const ConnectServicePromptDialogContainer = connect(null, mapDispatchToProps)(ConnectServicePromptDialog); diff --git a/packages/app/client/src/ui/dialogs/dataCollectionDialog/dataCollectionDialogContainer.ts b/packages/app/client/src/ui/dialogs/dataCollectionDialog/dataCollectionDialogContainer.ts index 1d23d5543..174312637 100644 --- a/packages/app/client/src/ui/dialogs/dataCollectionDialog/dataCollectionDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/dataCollectionDialog/dataCollectionDialogContainer.ts @@ -51,7 +51,4 @@ function mapDispatchToProps(dispatch: (action: Action) => void): DataCollectionD }; } -export const DataCollectionDialogContainer = connect( - null, - mapDispatchToProps -)(DataCollectionDialog); +export const DataCollectionDialogContainer = connect(null, mapDispatchToProps)(DataCollectionDialog); diff --git a/packages/app/client/src/ui/dialogs/getStartedWithCSDialog/getStartedWithCSDialogContainer.ts b/packages/app/client/src/ui/dialogs/getStartedWithCSDialog/getStartedWithCSDialogContainer.ts index 9a515af76..a4b0fe26c 100644 --- a/packages/app/client/src/ui/dialogs/getStartedWithCSDialog/getStartedWithCSDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/getStartedWithCSDialog/getStartedWithCSDialogContainer.ts @@ -63,7 +63,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void): GetStartedWithC }, }); -export const GetStartedWithCSDialogContainer = connect( - mapStateToProps, - mapDispatchToProps -)(GetStartedWithCSDialog); +export const GetStartedWithCSDialogContainer = connect(mapStateToProps, mapDispatchToProps)(GetStartedWithCSDialog); diff --git a/packages/app/client/src/ui/dialogs/openBotDialog/openBotDialogContainer.ts b/packages/app/client/src/ui/dialogs/openBotDialog/openBotDialogContainer.ts index 2ce0929cf..f04048185 100644 --- a/packages/app/client/src/ui/dialogs/openBotDialog/openBotDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/openBotDialog/openBotDialogContainer.ts @@ -75,7 +75,4 @@ const mapStateToProps = (state: RootState, ownProps: OpenBotDialogProps): OpenBo }; }; -export const OpenBotDialogContainer = connect( - mapStateToProps, - mapDispatchToProps -)(OpenBotDialog); +export const OpenBotDialogContainer = connect(mapStateToProps, mapDispatchToProps)(OpenBotDialog); diff --git a/packages/app/client/src/ui/dialogs/openUrlDialog/openUrlDialogContainer.ts b/packages/app/client/src/ui/dialogs/openUrlDialog/openUrlDialogContainer.ts index 80e9ddf4e..a7f377353 100644 --- a/packages/app/client/src/ui/dialogs/openUrlDialog/openUrlDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/openUrlDialog/openUrlDialogContainer.ts @@ -44,7 +44,4 @@ const mapDispatchToProps = (_dispatch: () => void): OpenUrlDialogProps => { }; }; -export const OpenUrlDialogContainer = connect( - null, - mapDispatchToProps -)(OpenUrlDialog); +export const OpenUrlDialogContainer = connect(null, mapDispatchToProps)(OpenUrlDialog); diff --git a/packages/app/client/src/ui/dialogs/postMigrationDialog/postMigrationDialogContainer.ts b/packages/app/client/src/ui/dialogs/postMigrationDialog/postMigrationDialogContainer.ts index fc5ce1c3a..6a5fd4e4e 100644 --- a/packages/app/client/src/ui/dialogs/postMigrationDialog/postMigrationDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/postMigrationDialog/postMigrationDialogContainer.ts @@ -53,7 +53,4 @@ function mapDispatchToProps(dispatch: (action: Action) => void): PostMigrationDi }; } -export const PostMigrationDialogContainer = connect( - mapStateToProps, - mapDispatchToProps -)(PostMigrationDialog); +export const PostMigrationDialogContainer = connect(mapStateToProps, mapDispatchToProps)(PostMigrationDialog); diff --git a/packages/app/client/src/ui/dialogs/progressIndicator/progressIndicatorContainer.ts b/packages/app/client/src/ui/dialogs/progressIndicator/progressIndicatorContainer.ts index c8732af16..24260bc81 100644 --- a/packages/app/client/src/ui/dialogs/progressIndicator/progressIndicatorContainer.ts +++ b/packages/app/client/src/ui/dialogs/progressIndicator/progressIndicatorContainer.ts @@ -55,7 +55,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void) => { }; }; -export const ProgressIndicatorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ProgressIndicator); +export const ProgressIndicatorContainer = connect(mapStateToProps, mapDispatchToProps)(ProgressIndicator); diff --git a/packages/app/client/src/ui/dialogs/resourcesSettings/resourcesSettingsContainer.ts b/packages/app/client/src/ui/dialogs/resourcesSettings/resourcesSettingsContainer.ts index 8eef35783..9535c5a7e 100644 --- a/packages/app/client/src/ui/dialogs/resourcesSettings/resourcesSettingsContainer.ts +++ b/packages/app/client/src/ui/dialogs/resourcesSettings/resourcesSettingsContainer.ts @@ -59,7 +59,4 @@ const mapDispatchToProps = dispatch => ({ ), cancel: () => DialogService.hideDialog(0), }); -export const ResourcesSettingsContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ResourcesSettings); +export const ResourcesSettingsContainer = connect(mapStateToProps, mapDispatchToProps)(ResourcesSettings); diff --git a/packages/app/client/src/ui/dialogs/secretPromptDialog/secretPromptDialogContainer.ts b/packages/app/client/src/ui/dialogs/secretPromptDialog/secretPromptDialogContainer.ts index 628ca257b..f43f93a76 100644 --- a/packages/app/client/src/ui/dialogs/secretPromptDialog/secretPromptDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/secretPromptDialog/secretPromptDialogContainer.ts @@ -49,7 +49,4 @@ function mapDispatchToProps(dispatch: (action: Action) => void): SecretPromptDia }; } -export const SecretPromptDialogContainer = connect( - undefined, - mapDispatchToProps -)(SecretPromptDialog); +export const SecretPromptDialogContainer = connect(undefined, mapDispatchToProps)(SecretPromptDialog); diff --git a/packages/app/client/src/ui/dialogs/tabManager/tabManagerContainer.ts b/packages/app/client/src/ui/dialogs/tabManager/tabManagerContainer.ts index 388de1b76..180ffc5cc 100644 --- a/packages/app/client/src/ui/dialogs/tabManager/tabManagerContainer.ts +++ b/packages/app/client/src/ui/dialogs/tabManager/tabManagerContainer.ts @@ -48,7 +48,4 @@ const mapDispatchToProps = (dispatch): TabManagerProps => ({ }, }); -export const TabManagerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(TabManager) as any; +export const TabManagerContainer = connect(mapStateToProps, mapDispatchToProps)(TabManager) as any; diff --git a/packages/app/client/src/ui/dialogs/updateAvailableDialog/updateAvailableDialogContainer.ts b/packages/app/client/src/ui/dialogs/updateAvailableDialog/updateAvailableDialogContainer.ts index 0c39d5686..27aaf4c85 100644 --- a/packages/app/client/src/ui/dialogs/updateAvailableDialog/updateAvailableDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/updateAvailableDialog/updateAvailableDialogContainer.ts @@ -46,7 +46,4 @@ function mapDispatchToProps(_dispatch: any): UpdateAvailableDialogProps { }; } -export const UpdateAvailableDialogContainer = connect( - null, - mapDispatchToProps -)(UpdateAvailableDialog); +export const UpdateAvailableDialogContainer = connect(null, mapDispatchToProps)(UpdateAvailableDialog); diff --git a/packages/app/client/src/ui/dialogs/updateUnavailableDialog/updateUnavailableDialogContainer.ts b/packages/app/client/src/ui/dialogs/updateUnavailableDialog/updateUnavailableDialogContainer.ts index 937bd8e4a..4070d4106 100644 --- a/packages/app/client/src/ui/dialogs/updateUnavailableDialog/updateUnavailableDialogContainer.ts +++ b/packages/app/client/src/ui/dialogs/updateUnavailableDialog/updateUnavailableDialogContainer.ts @@ -43,7 +43,4 @@ function mapDispatchToProps(_dispatch: any): UpdateUnavailableDialogProps { }; } -export const UpdateUnavailableDialogContainer = connect( - null, - mapDispatchToProps -)(UpdateUnavailableDialog); +export const UpdateUnavailableDialogContainer = connect(null, mapDispatchToProps)(UpdateUnavailableDialog); diff --git a/packages/app/client/src/ui/editor/appSettingsEditor/appSettingsEditorContainer.ts b/packages/app/client/src/ui/editor/appSettingsEditor/appSettingsEditorContainer.ts index 46bd84ead..44302cd5b 100644 --- a/packages/app/client/src/ui/editor/appSettingsEditor/appSettingsEditorContainer.ts +++ b/packages/app/client/src/ui/editor/appSettingsEditor/appSettingsEditorContainer.ts @@ -73,7 +73,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void, ownProps: AppSet setDirtyFlag: debounce((dirty: boolean) => dispatch(EditorActions.setDirtyFlag(ownProps.documentId, dirty)), 300), }); -export const AppSettingsEditorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(AppSettingsEditor); +export const AppSettingsEditorContainer = connect(mapStateToProps, mapDispatchToProps)(AppSettingsEditor); diff --git a/packages/app/client/src/ui/editor/emulator/chatPanel/chatPanelContainer.ts b/packages/app/client/src/ui/editor/emulator/chatPanel/chatPanelContainer.ts index 72c12c244..1dfc71d6c 100644 --- a/packages/app/client/src/ui/editor/emulator/chatPanel/chatPanelContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/chatPanel/chatPanelContainer.ts @@ -44,7 +44,4 @@ function mapStateToProps(state: RootState, { documentId }: { documentId: string }; } -export const ChatPanelContainer = connect( - mapStateToProps, - undefined -)(ChatPanel); +export const ChatPanelContainer = connect(mapStateToProps, undefined)(ChatPanel); diff --git a/packages/app/client/src/ui/editor/emulator/emulatorContainer.ts b/packages/app/client/src/ui/editor/emulator/emulatorContainer.ts index c1bc076a9..05b4aa1cd 100644 --- a/packages/app/client/src/ui/editor/emulator/emulatorContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/emulatorContainer.ts @@ -85,7 +85,4 @@ const mapDispatchToProps = (dispatch): EmulatorProps => ({ ), }); -export const EmulatorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(Emulator); +export const EmulatorContainer = connect(mapStateToProps, mapDispatchToProps)(Emulator); diff --git a/packages/app/client/src/ui/editor/emulator/parts/chat/chatContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/chat/chatContainer.ts index dc5dc7e06..5e26b2cb9 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/chat/chatContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/chat/chatContainer.ts @@ -79,7 +79,4 @@ const mapDispatchToProps = (dispatch, ownProps: ChatProps): Partial = }; }; -export const ChatContainer = connect( - mapStateToProps, - mapDispatchToProps -)(Chat); +export const ChatContainer = connect(mapStateToProps, mapDispatchToProps)(Chat); diff --git a/packages/app/client/src/ui/editor/emulator/parts/chat/outerActivityWrapperContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/chat/outerActivityWrapperContainer.ts index d81b9f563..e8b12ea50 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/chat/outerActivityWrapperContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/chat/outerActivityWrapperContainer.ts @@ -56,7 +56,4 @@ function mapStateToProps(state: RootState, { documentId }: { documentId: string }; } -export const OuterActivityWrapperContainer = connect( - mapStateToProps, - undefined -)(OuterActivityWrapper); +export const OuterActivityWrapperContainer = connect(mapStateToProps, undefined)(OuterActivityWrapper); diff --git a/packages/app/client/src/ui/editor/emulator/parts/chat/traceActivityContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/chat/traceActivityContainer.ts index 609b73be2..3cc790f15 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/chat/traceActivityContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/chat/traceActivityContainer.ts @@ -56,7 +56,4 @@ function mapStateToProps(state: RootState, { documentId }: { documentId: string }; } -export const TraceActivityContainer = connect( - mapStateToProps, - undefined -)(TraceActivity); +export const TraceActivityContainer = connect(mapStateToProps, undefined)(TraceActivity); diff --git a/packages/app/client/src/ui/editor/emulator/parts/inspector/inspectorContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/inspector/inspectorContainer.ts index df0f172cb..1ec56a44f 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/inspector/inspectorContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/inspector/inspectorContainer.ts @@ -72,7 +72,4 @@ const mapDispatchToProps = dispatch => { }; }; -export const InspectorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(Inspector); +export const InspectorContainer = connect(mapStateToProps, mapDispatchToProps)(Inspector); diff --git a/packages/app/client/src/ui/editor/emulator/parts/log/logContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/log/logContainer.ts index c725043c2..551ab7d25 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/log/logContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/log/logContainer.ts @@ -43,7 +43,4 @@ function mapStateToProps(state: RootState, { documentId }: { documentId: string }; } -export const LogContainer = connect( - mapStateToProps, - undefined -)(Log); +export const LogContainer = connect(mapStateToProps, undefined)(Log); diff --git a/packages/app/client/src/ui/editor/emulator/parts/log/logEntryContainer.ts b/packages/app/client/src/ui/editor/emulator/parts/log/logEntryContainer.ts index 0334bc4f3..afef28923 100644 --- a/packages/app/client/src/ui/editor/emulator/parts/log/logEntryContainer.ts +++ b/packages/app/client/src/ui/editor/emulator/parts/log/logEntryContainer.ts @@ -83,7 +83,4 @@ function mapDispatchToProps(dispatch: any): Partial { }; } -export const LogEntry = connect( - null, - mapDispatchToProps -)(LogEntryComponent); +export const LogEntry = connect(null, mapDispatchToProps)(LogEntryComponent); diff --git a/packages/app/client/src/ui/editor/recentBotsList/recentBotsListContainer.ts b/packages/app/client/src/ui/editor/recentBotsList/recentBotsListContainer.ts index d21e0c5b8..ef817d564 100644 --- a/packages/app/client/src/ui/editor/recentBotsList/recentBotsListContainer.ts +++ b/packages/app/client/src/ui/editor/recentBotsList/recentBotsListContainer.ts @@ -56,7 +56,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void): RecentBotsListP }; }; -export const RecentBotsListContainer = connect( - mapStateToProps, - mapDispatchToProps -)(RecentBotsList); +export const RecentBotsListContainer = connect(mapStateToProps, mapDispatchToProps)(RecentBotsList); diff --git a/packages/app/client/src/ui/editor/welcomePage/howToBuildABotContainer.ts b/packages/app/client/src/ui/editor/welcomePage/howToBuildABotContainer.ts index 5c7985ed1..5bfecf169 100644 --- a/packages/app/client/src/ui/editor/welcomePage/howToBuildABotContainer.ts +++ b/packages/app/client/src/ui/editor/welcomePage/howToBuildABotContainer.ts @@ -47,7 +47,4 @@ function mapDispatchToProps(dispatch: (action: Action) => void): HowToBuildABotP }; } -export const HowToBuildABotContainer = connect( - undefined, - mapDispatchToProps -)(HowToBuildABot); +export const HowToBuildABotContainer = connect(undefined, mapDispatchToProps)(HowToBuildABot); diff --git a/packages/app/client/src/ui/editor/welcomePage/welcomePageContainer.ts b/packages/app/client/src/ui/editor/welcomePage/welcomePageContainer.ts index 206366881..ff045d726 100644 --- a/packages/app/client/src/ui/editor/welcomePage/welcomePageContainer.ts +++ b/packages/app/client/src/ui/editor/welcomePage/welcomePageContainer.ts @@ -70,7 +70,4 @@ function mapDispatchToProps(dispatch: (action: Action) => void): WelcomePageProp } // export const WelcomePage = connect(mapStateToProps, mapDispatchToProps)(hot(module)(WelcomePageComp)) as any; -export const WelcomePageContainer = connect( - mapStateToProps, - mapDispatchToProps -)(WelcomePage); +export const WelcomePageContainer = connect(mapStateToProps, mapDispatchToProps)(WelcomePage); diff --git a/packages/app/client/src/ui/shell/appMenu/appMenu.spec.tsx b/packages/app/client/src/ui/shell/appMenu/appMenu.spec.tsx index db018f3a3..09a001b7c 100644 --- a/packages/app/client/src/ui/shell/appMenu/appMenu.spec.tsx +++ b/packages/app/client/src/ui/shell/appMenu/appMenu.spec.tsx @@ -127,7 +127,11 @@ describe('', () => { it('should generate the theme menu items', () => { instance.props = { ...instance.props, - availableThemes: [{ name: 'Light', href: '' }, { name: 'Dark', href: '' }, { name: 'High contrast', href: '' }], + availableThemes: [ + { name: 'Light', href: '' }, + { name: 'Dark', href: '' }, + { name: 'High contrast', href: '' }, + ], currentTheme: 'Light', }; const themeItems: MenuItem[] = (instance as any).getThemeMenuItems(); diff --git a/packages/app/client/src/ui/shell/appMenu/appMenuContainer.ts b/packages/app/client/src/ui/shell/appMenu/appMenuContainer.ts index 3f66a9dd0..d273cfb56 100644 --- a/packages/app/client/src/ui/shell/appMenu/appMenuContainer.ts +++ b/packages/app/client/src/ui/shell/appMenu/appMenuContainer.ts @@ -93,7 +93,4 @@ function mapDispatchToProps(dispatch): AppMenuProps { }; } -export const AppMenuContainer = connect( - mapStateToProps, - mapDispatchToProps -)(AppMenu); +export const AppMenuContainer = connect(mapStateToProps, mapDispatchToProps)(AppMenu); diff --git a/packages/app/client/src/ui/shell/explorer/botNotOpenExplorer/botNotOpenExplorerContainer.ts b/packages/app/client/src/ui/shell/explorer/botNotOpenExplorer/botNotOpenExplorerContainer.ts index 4ff7abcdb..8f24d32ff 100644 --- a/packages/app/client/src/ui/shell/explorer/botNotOpenExplorer/botNotOpenExplorerContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/botNotOpenExplorer/botNotOpenExplorerContainer.ts @@ -60,7 +60,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void): BotNotOpenExplo }), }); -export const BotNotOpenExplorerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(BotNotOpenExplorerComp); +export const BotNotOpenExplorerContainer = connect(mapStateToProps, mapDispatchToProps)(BotNotOpenExplorerComp); diff --git a/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointEditor/endpointEditorContainer.ts b/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointEditor/endpointEditorContainer.ts index f6c83b11c..8e4457d83 100644 --- a/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointEditor/endpointEditorContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointEditor/endpointEditorContainer.ts @@ -66,7 +66,4 @@ const mapDispatchToProps = dispatch => (): Partial => { }; }; -export const EndpointEditorContainer = connect( - mapStateToProps, - mapDispatchToProps -)(EndpointEditor) as any; +export const EndpointEditorContainer = connect(mapStateToProps, mapDispatchToProps)(EndpointEditor) as any; diff --git a/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointExplorerContainer.ts b/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointExplorerContainer.ts index a3d6059a9..4b53a199a 100644 --- a/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointExplorerContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/endpointExplorer/endpointExplorerContainer.ts @@ -67,7 +67,4 @@ const mapDispatchToProps = dispatch => { }; }; -export const EndpointExplorerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(EndpointExplorer as any) as any; +export const EndpointExplorerContainer = connect(mapStateToProps, mapDispatchToProps)(EndpointExplorer as any) as any; diff --git a/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notification.tsx b/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notification.tsx index 023092367..94e80d176 100644 --- a/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notification.tsx +++ b/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notification.tsx @@ -105,7 +105,4 @@ const mapDispatchToProps = (dispatch): NotificationProps => ({ const mapStateToProps = (): NotificationProps => ({}); -export const Notification = connect( - mapStateToProps, - mapDispatchToProps -)(NotificationComp); +export const Notification = connect(mapStateToProps, mapDispatchToProps)(NotificationComp); diff --git a/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notificationsExplorer.tsx b/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notificationsExplorer.tsx index 56ffaaaa9..897266d90 100644 --- a/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notificationsExplorer.tsx +++ b/packages/app/client/src/ui/shell/explorer/notificationsExplorer/notificationsExplorer.tsx @@ -97,7 +97,4 @@ const mapDispatchToProps = (dispatch): NotificationExplorerProps => { }; }; -export const NotificationsExplorer = connect( - mapStateToProps, - mapDispatchToProps -)(NotificationsExplorerComp); +export const NotificationsExplorer = connect(mapStateToProps, mapDispatchToProps)(NotificationsExplorerComp); diff --git a/packages/app/client/src/ui/shell/explorer/resourceExplorer/resourceExplorerContainer.ts b/packages/app/client/src/ui/shell/explorer/resourceExplorer/resourceExplorerContainer.ts index 7ed3b8ad2..9e5c217a8 100644 --- a/packages/app/client/src/ui/shell/explorer/resourceExplorer/resourceExplorerContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/resourceExplorer/resourceExplorerContainer.ts @@ -57,7 +57,4 @@ const mapDispatchToProps = (dispatch: (...args: any[]) => void): ResourceExplore window, }); -export const ResourceExplorerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ResourceExplorer); +export const ResourceExplorerContainer = connect(mapStateToProps, mapDispatchToProps)(ResourceExplorer); diff --git a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/connectedServiceEditorContainer.ts b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/connectedServiceEditorContainer.ts index 1f64cbce4..bef363227 100644 --- a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/connectedServiceEditorContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/connectedServiceEditorContainer.ts @@ -50,7 +50,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void) => { }; }; -export const ConnectedServiceEditorContainer = connect( - null, - mapDispatchToProps -)(ConnectedServiceEditor) as any; +export const ConnectedServiceEditorContainer = connect(null, mapDispatchToProps)(ConnectedServiceEditor) as any; diff --git a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.spec.tsx b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.spec.tsx index 7ee177ceb..b4f115704 100644 --- a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.spec.tsx +++ b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.spec.tsx @@ -45,13 +45,23 @@ describe('The KvPair component', () => { }); it('should render a key value pair row for each pair', () => { - node.setState({ kvPairs: [{ key: 'key1', value: 'val1' }, { key: 'key2', value: 'val2' }], numRows: 2 }); + node.setState({ + kvPairs: [ + { key: 'key1', value: 'val1' }, + { key: 'key2', value: 'val2' }, + ], + numRows: 2, + }); expect(node.find('ul').children()).toHaveLength(2); }); it('should call the onChange callback with the updated kv pairs', () => { - const kvPairs = [{ key: 'key1', value: 'val1' }, { key: '', value: '' }, { key: 'key3', value: 'val3' }]; + const kvPairs = [ + { key: 'key1', value: 'val1' }, + { key: '', value: '' }, + { key: 'key3', value: 'val3' }, + ]; node.setState({ kvPairs, numRows: 3 }); // update value of row 3 const mockChangeEvent = { target: { dataset: { index: 2, prop: 'value' }, value: 'updatedValue3' } }; @@ -72,13 +82,19 @@ describe('The KvPair component', () => { expect(node.instance().state).toEqual({ alert: '', - kvPairs: [{ key: 'key1', value: 'val1' }, { key: '', value: '' }], + kvPairs: [ + { key: 'key1', value: 'val1' }, + { key: '', value: '' }, + ], numRows: 2, }); }); it('should remove a key value pair', () => { - const mockKvPairs = [{ key: 'key1', value: 'val1' }, { key: 'key2', value: 'val2' }]; + const mockKvPairs = [ + { key: 'key1', value: 'val1' }, + { key: 'key2', value: 'val2' }, + ]; node.setState({ kvPairs: mockKvPairs, numRows: 2 }); node.instance().onRemoveKvPair(); diff --git a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.tsx b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.tsx index 79aae113e..661b73168 100644 --- a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.tsx +++ b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServiceEditor/kvPair.tsx @@ -150,15 +150,12 @@ export class KvPair extends Component { // trims off any incomplete pairs private pruneIncompletePairs(kvPairs: { key: string; value: string }[]): { [key: string]: string } { - return kvPairs.reduce( - (kvPairs, kvPair) => { - if (kvPair.key && kvPair.key.trim() && kvPair.value && kvPair.value.trim()) { - kvPairs[kvPair.key] = kvPair.value; - } - return kvPairs; - }, - {} as any - ); + return kvPairs.reduce((kvPairs, kvPair) => { + if (kvPair.key && kvPair.key.trim() && kvPair.value && kvPair.value.trim()) { + kvPairs[kvPair.key] = kvPair.value; + } + return kvPairs; + }, {} as any); } private get alert(): ReactNode { diff --git a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServicePicker/connectedServicePickerContainer.ts b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServicePicker/connectedServicePickerContainer.ts index 23ae93c12..12b89c8af 100644 --- a/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServicePicker/connectedServicePickerContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/servicesExplorer/connectedServicePicker/connectedServicePickerContainer.ts @@ -60,7 +60,4 @@ const mapDispatchToProps = (dispatch: (action: Action) => void) => { }; }; -export const ConnectedServicePickerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ConnectedServicePicker); +export const ConnectedServicePickerContainer = connect(mapStateToProps, mapDispatchToProps)(ConnectedServicePicker); diff --git a/packages/app/client/src/ui/shell/explorer/servicesExplorer/servicesExplorerContainer.ts b/packages/app/client/src/ui/shell/explorer/servicesExplorer/servicesExplorerContainer.ts index 6b6d69841..f914f82ea 100644 --- a/packages/app/client/src/ui/shell/explorer/servicesExplorer/servicesExplorerContainer.ts +++ b/packages/app/client/src/ui/shell/explorer/servicesExplorer/servicesExplorerContainer.ts @@ -87,7 +87,4 @@ const mapDispatchToProps = (dispatch): Partial => { }; }; -export const ServicesExplorerContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ServicesExplorer); +export const ServicesExplorerContainer = connect(mapStateToProps, mapDispatchToProps)(ServicesExplorer); diff --git a/packages/app/client/src/ui/shell/mainContainer.ts b/packages/app/client/src/ui/shell/mainContainer.ts index 934971704..a5a3a9066 100644 --- a/packages/app/client/src/ui/shell/mainContainer.ts +++ b/packages/app/client/src/ui/shell/mainContainer.ts @@ -68,7 +68,4 @@ const mapDispatchToProps = (dispatch): MainProps => ({ }, }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(Main); +export default connect(mapStateToProps, mapDispatchToProps)(Main); diff --git a/packages/app/client/src/ui/shell/mdi/documents/documentsContainer.ts b/packages/app/client/src/ui/shell/mdi/documents/documentsContainer.ts index f5ad77fdc..6ebc474da 100644 --- a/packages/app/client/src/ui/shell/mdi/documents/documentsContainer.ts +++ b/packages/app/client/src/ui/shell/mdi/documents/documentsContainer.ts @@ -47,7 +47,4 @@ function mapStateToProps(state: RootState, ownProps: DocumentsProps): DocumentsP }; } -export const DocumentsContainer = connect( - mapStateToProps, - null -)(Documents); +export const DocumentsContainer = connect(mapStateToProps, null)(Documents); diff --git a/packages/app/client/src/ui/shell/mdi/mdiContainer.ts b/packages/app/client/src/ui/shell/mdi/mdiContainer.ts index 6ce31d351..e302e0baa 100644 --- a/packages/app/client/src/ui/shell/mdi/mdiContainer.ts +++ b/packages/app/client/src/ui/shell/mdi/mdiContainer.ts @@ -46,7 +46,4 @@ const mapStateToProps = (state: RootState, ownProps: MDIProps): MDIProps => ({ presentationModeEnabled: state.presentation.enabled, }); -export const MDI = connect( - mapStateToProps, - null -)(MDIComponent); +export const MDI = connect(mapStateToProps, null)(MDIComponent); diff --git a/packages/app/client/src/ui/shell/mdi/tab/tabContainer.ts b/packages/app/client/src/ui/shell/mdi/tab/tabContainer.ts index cf1f37123..a6f975e45 100644 --- a/packages/app/client/src/ui/shell/mdi/tab/tabContainer.ts +++ b/packages/app/client/src/ui/shell/mdi/tab/tabContainer.ts @@ -43,7 +43,4 @@ const mapDispatchToProps = (dispatch, ownProps: TabProps): TabProps => ({ dispatch(swapTabs(editorKey, owningEditor, tabId, ownProps.documentId)), }); -export const TabContainer = connect( - null, - mapDispatchToProps -)(Tab); +export const TabContainer = connect(null, mapDispatchToProps)(Tab); diff --git a/packages/app/client/src/ui/shell/mdi/tabBar/tabBarContainer.ts b/packages/app/client/src/ui/shell/mdi/tabBar/tabBarContainer.ts index 768328c44..eed9ed560 100644 --- a/packages/app/client/src/ui/shell/mdi/tabBar/tabBarContainer.ts +++ b/packages/app/client/src/ui/shell/mdi/tabBar/tabBarContainer.ts @@ -73,7 +73,4 @@ const mapDispatchToProps = (dispatch): TabBarProps => ({ }, }); -export const TabBarContainer = connect( - mapStateToProps, - mapDispatchToProps -)(TabBar); +export const TabBarContainer = connect(mapStateToProps, mapDispatchToProps)(TabBar); diff --git a/packages/app/client/src/ui/shell/mdi/tabbedDocument/contentOverlay/contentOverlay.tsx b/packages/app/client/src/ui/shell/mdi/tabbedDocument/contentOverlay/contentOverlay.tsx index 54928801d..532c3c359 100644 --- a/packages/app/client/src/ui/shell/mdi/tabbedDocument/contentOverlay/contentOverlay.tsx +++ b/packages/app/client/src/ui/shell/mdi/tabbedDocument/contentOverlay/contentOverlay.tsx @@ -126,7 +126,4 @@ const mapDispatchToProps = (dispatch): ContentOverlayProps => ({ dispatch(EditorActions.appendTab(editorKey, owningEditor, tabId)), }); -export const ContentOverlay = connect( - mapStateToProps, - mapDispatchToProps -)(ContentOverlayComponent) as any; +export const ContentOverlay = connect(mapStateToProps, mapDispatchToProps)(ContentOverlayComponent) as any; diff --git a/packages/app/client/src/ui/shell/mdi/tabbedDocument/leftContentOverlay/leftContentOverlay.tsx b/packages/app/client/src/ui/shell/mdi/tabbedDocument/leftContentOverlay/leftContentOverlay.tsx index 418beb948..d26c5c48c 100644 --- a/packages/app/client/src/ui/shell/mdi/tabbedDocument/leftContentOverlay/leftContentOverlay.tsx +++ b/packages/app/client/src/ui/shell/mdi/tabbedDocument/leftContentOverlay/leftContentOverlay.tsx @@ -106,7 +106,4 @@ const mapDispatchToProps = (dispatch): LeftContentOverlayProps => ({ }, }); -export const LeftContentOverlay = connect( - mapStateToProps, - mapDispatchToProps -)(LeftContentOverlayComponent); +export const LeftContentOverlay = connect(mapStateToProps, mapDispatchToProps)(LeftContentOverlayComponent); diff --git a/packages/app/client/src/ui/shell/mdi/tabbedDocument/rightContentOverlay/rightContentOverlay.tsx b/packages/app/client/src/ui/shell/mdi/tabbedDocument/rightContentOverlay/rightContentOverlay.tsx index 62d5f381e..56b608ca2 100644 --- a/packages/app/client/src/ui/shell/mdi/tabbedDocument/rightContentOverlay/rightContentOverlay.tsx +++ b/packages/app/client/src/ui/shell/mdi/tabbedDocument/rightContentOverlay/rightContentOverlay.tsx @@ -114,7 +114,4 @@ const mapDispatchToProps = (dispatch): RightContentOverlayProps => ({ dispatch(EditorActions.splitTab(contentType, tabId, Constants.EDITOR_KEY_PRIMARY, Constants.EDITOR_KEY_SECONDARY)), }); -export const RightContentOverlay = connect( - mapStateToProps, - mapDispatchToProps -)(RightContentOverlayComponent); +export const RightContentOverlay = connect(mapStateToProps, mapDispatchToProps)(RightContentOverlayComponent); diff --git a/packages/app/client/src/ui/shell/navBar/navBarContainer.ts b/packages/app/client/src/ui/shell/navBar/navBarContainer.ts index 3b217639c..65aa5625f 100644 --- a/packages/app/client/src/ui/shell/navBar/navBarContainer.ts +++ b/packages/app/client/src/ui/shell/navBar/navBarContainer.ts @@ -66,7 +66,4 @@ const mapDispatchToProps = (dispatch): NavBarProps => ({ dispatch(executeCommand(true, SharedConstants.Commands.Telemetry.TrackEvent, null, name, properties)), }); -export const NavBar = connect( - mapStateToProps, - mapDispatchToProps -)(NavBarComponent); +export const NavBar = connect(mapStateToProps, mapDispatchToProps)(NavBarComponent); diff --git a/packages/app/main/package-lock.json b/packages/app/main/package-lock.json index 38c0bc2d0..d58e18b9a 100644 --- a/packages/app/main/package-lock.json +++ b/packages/app/main/package-lock.json @@ -1,6 +1,6 @@ { "name": "@bfemulator/main", - "version": "4.5.2", + "version": "4.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -725,6 +725,812 @@ } } } + }, + "restify": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/restify/-/restify-8.4.0.tgz", + "integrity": "sha512-yqS/wJI0ZU78whO2VfCCnFY7/JSqJt7wTDIdaQUo/a4TzAaC5KXUzxbs+xW4afJCk3NefGYYuiSrFSBWwVw/NA==", + "requires": { + "assert-plus": "^1.0.0", + "bunyan": "^1.8.12", + "csv": "^5.1.1", + "dtrace-provider": "^0.8.1", + "escape-regexp-component": "^1.0.2", + "ewma": "^2.0.1", + "find-my-way": "^2.0.1", + "formidable": "^1.2.1", + "http-signature": "^1.2.0", + "lodash": "^4.17.11", + "lru-cache": "^5.1.1", + "mime": "^2.4.3", + "negotiator": "^0.6.2", + "once": "^1.4.0", + "pidusage": "^2.0.17", + "qs": "^6.7.0", + "restify-errors": "^8.0.0", + "semver": "^6.1.1", + "send": "^0.16.2", + "spdy": "^4.0.0", + "uuid": "^3.3.2", + "vasync": "^2.2.0" + }, + "dependencies": { + "@netflix/nerror": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.2.tgz", + "integrity": "sha512-c01MmkM3Oi0BkTV4odMpr+58uXlxRKUPcu1ONR+sU3YAFAW4pP1j2b0opS9jX+an3ldpBJtiompzAEFZdlc8YQ==", + "requires": { + "assert-plus": "^1.0.0", + "extsprintf": "^1.4.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "extsprintf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", + "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=" + } + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "csv": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.1.3.tgz", + "integrity": "sha512-uHPF5nxxFgcBQ/Mkicjh+IcQJeooIcN8gS/5mnvIdIccLh3Qf792jXE00ovdYDmABhE0yTMNCZgx3ZsBrR2GoQ==", + "requires": { + "csv-generate": "^3.2.3", + "csv-parse": "^4.4.6", + "csv-stringify": "^5.3.3", + "stream-transform": "^2.0.1" + } + }, + "csv-generate": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.3.tgz", + "integrity": "sha512-IcR3K0Nx+nJAkcU2eAglVR7DuHnxcuhUM2w2cR+aHOW7bZp2S5LyN2HF3zTkp6BV/DjR6ykoKznUm+AjnWcOKg==" + }, + "csv-parse": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.6.5.tgz", + "integrity": "sha512-tUohmlM5X1Wtn7aRA4FsJMmnvGo+GUknK/Dp+//ms7pvpXADda5HIi5vFYOvAs/WSn5JUM1bt2AT3TxtDFV3Cw==", + "requires": { + "pad": "^3.2.0" + } + }, + "csv-stringify": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.3.3.tgz", + "integrity": "sha512-q8Qj+/lN74LRmG7Mg0LauE5WcnJOD5MEGe1gI57IYJCB61KWuEbAFHm1uIPDkI26aqElyBB57SlE2GGwq2EY5A==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-regexp-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", + "integrity": "sha1-nGO20LJf8qiMOtvRjFthrMO5+qI=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "ewma": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", + "integrity": "sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, + "find-my-way": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.1.tgz", + "integrity": "sha512-pzZA9/PlhDGG5PRzmd4vH4AbKW7FO68RE7q2I3NzjJHcVPukYbDA7bPdArg7ySKfS6pKki+qhrawFoN6aNZfjA==", + "requires": { + "fast-decode-uri-component": "^1.0.0", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-signature": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.1.tgz", + "integrity": "sha512-Y29YKEc8MQsjch/VzkUVJ+2MXd9WcR42fK5u36CZf4G8bXw2DXMTWuESiB0R6m59JAWxlPPw5/Fri/t/AyyueA==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.14.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true + }, + "mixme": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.3.2.tgz", + "integrity": "sha512-tilCZOvIhRETXJuTmxxpz8mgplF7gmFhcH05JuR/YL+JLO98gLRQ1Mk4XpYQxxbPMKupSOv+Bidw7EKv8wds1w==" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "optional": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "optional": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "pad": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pad/-/pad-3.2.0.tgz", + "integrity": "sha512-2u0TrjcGbOjBTJpyewEl4hBO3OeX5wWue7eIFPzQTg6wFSvoaHcBTTUY5m+n0hd04gmTCPuY0kCpVIVuw5etwg==", + "requires": { + "wcwidth": "^1.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "optional": true + }, + "pidusage": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.17.tgz", + "integrity": "sha512-N8X5v18rBmlBoArfS83vrnD0gIFyZkXEo7a5pAS2aT0i2OLVymFb2AzVg+v8l/QcXnE1JwZcaXR8daJcoJqtjw==", + "requires": { + "safe-buffer": "^5.1.2" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "restify-errors": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-8.0.1.tgz", + "integrity": "sha512-EFQpxS828J0SBTNuJjh+rHD0OE8BoqnaxMAzuKHRNnGt5BV/212HHQIelZG4zjZYpTDEiuVAhQYHwSGSzAz0Ag==", + "requires": { + "@netflix/nerror": "^1.0.0", + "assert-plus": "^1.0.0", + "lodash": "^4.17.15", + "safe-json-stringify": "^1.0.4" + } + }, + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "optional": true + }, + "safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "requires": { + "ret": "~0.2.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "semver-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", + "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + } + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "stream-transform": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.1.tgz", + "integrity": "sha512-GiTcO/rRvZP2R8WPwxmxCFP+Of1yIATuFAmYkvSLDfcD93X2WHiPwdgIqeFT2CvL1gyAsjQvu1nB6RDNQ5b2jw==", + "requires": { + "mixme": "^0.3.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "vasync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.0.tgz", + "integrity": "sha1-z951GGChWCLbOxMrxZsRakra8Bs=", + "requires": { + "verror": "1.10.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "^1.0.3" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } } } } diff --git a/packages/app/main/package.json b/packages/app/main/package.json index 66f5f224f..0abc665a9 100644 --- a/packages/app/main/package.json +++ b/packages/app/main/package.json @@ -88,7 +88,7 @@ "@types/mkdirp": "^0.5.2", "@types/node": "8.9.3", "@types/request": "^2.47.0", - "@types/restify": "^5.0.7", + "@types/restify": "^8.4.1", "@types/semver": "^5.5.0", "@types/ws": "^4.0.1", "asar-integrity": "^0.2.4", @@ -125,7 +125,6 @@ "@babel/runtime": "^7.1.5", "@bfemulator/app-shared": "^1.0.0", "@bfemulator/client": "^1.0.0", - "@bfemulator/emulator-core": "^1.0.0-0", "@bfemulator/extension-json": "^1.0.0", "@bfemulator/extension-luis": "^1.0.0", "@bfemulator/extension-qnamaker": "^1.0.0", @@ -154,7 +153,7 @@ "read-text-file": "^1.1.0", "redux": "^3.7.2", "redux-saga": "^0.16.0", - "restify": "^5.0.0", + "restify": "^8.4.0", "restify-cors-middleware": "^1.1.0", "rsa-pem-from-mod-exp": "^0.8.4", "sanitize-filename": "^1.6.1", diff --git a/packages/app/main/src/appMenuBuilder.spec.ts b/packages/app/main/src/appMenuBuilder.spec.ts index 8a7e46eea..ae7b23910 100644 --- a/packages/app/main/src/appMenuBuilder.spec.ts +++ b/packages/app/main/src/appMenuBuilder.spec.ts @@ -140,6 +140,7 @@ jest.mock('./appUpdater', () => ({ jest.mock('./emulator', () => ({ Emulator: { + initialize: jest.fn(), getInstance: () => ({ ngrok: { broadcastNgrokExpired: () => null, diff --git a/packages/app/main/src/appUpdater.spec.ts b/packages/app/main/src/appUpdater.spec.ts index 2c491d835..add29dcab 100644 --- a/packages/app/main/src/appUpdater.spec.ts +++ b/packages/app/main/src/appUpdater.spec.ts @@ -53,6 +53,12 @@ const defaultSettings = { let mockSettings: any; +jest.mock('./appMenuBuilder', () => ({ + AppMenuBuilder: { + refreshAppUpdateMenu: jest.fn(), + }, +})); + jest.mock('electron-updater', () => ({ get autoUpdater() { return mockAutoUpdater; @@ -131,6 +137,7 @@ jest.mock('./utils/sendNotificationToClient', () => ({ jest.mock('./emulator', () => ({ Emulator: { + initialize: jest.fn(), getInstance: () => ({ ngrok: { ngrokEmitter: { diff --git a/packages/app/main/src/botFrameworkService.ts b/packages/app/main/src/botFrameworkService.ts deleted file mode 100644 index 9b403d23a..000000000 --- a/packages/app/main/src/botFrameworkService.ts +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { LogLevel, textItem } from '@bfemulator/sdk-shared'; -import { newNotification, SharedConstants } from '@bfemulator/app-shared'; -import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared'; - -import { emulatorApplication } from './main'; -import { RestServer } from './restServer'; - -/** - * Communicates with the bot. - */ -export class BotFrameworkService { - @CommandServiceInstance() - private commandService: CommandServiceImpl; - - public server: RestServer; - private _serverUrl: string; - private _serverPort: number; - - public get serverUrl() { - return this._serverUrl; - } - - public get serverPort() { - return this._serverPort; - } - - /** - * Applies configuration changes. - */ - public async recycle(port: number) { - if (this.server) { - await this.server.close(); - } - - this.server = new RestServer(); - try { - const { url, port: serverChosenPort } = await this.server.listen(port); - - this._serverUrl = url; - this._serverPort = serverChosenPort; - } catch (e) { - if (e.code === 'EADDRINUSE') { - const notification = newNotification( - `Port ${port} is in use and the Emulator cannot start. Please free this port so the emulator can use it.` - ); - await this.commandService.remoteCall(SharedConstants.Commands.Notifications.Add, notification); - } - } - } - - public report(conversationId: string) { - const serverUrl = this.serverUrl.replace('[::]', 'localhost'); - emulatorApplication.mainWindow.logService.logToChat( - conversationId, - textItem(LogLevel.Debug, `Emulator listening on ${serverUrl}`) - ); - } -} diff --git a/packages/app/main/src/botHelpers.ts b/packages/app/main/src/botHelpers.ts index 67b91c647..b52205ffa 100644 --- a/packages/app/main/src/botHelpers.ts +++ b/packages/app/main/src/botHelpers.ts @@ -34,7 +34,6 @@ import * as path from 'path'; import * as electron from 'electron'; -import { Conversation } from '@bfemulator/emulator-core'; import { BotInfo, getBotDisplayName, SharedConstants } from '@bfemulator/app-shared'; import { BotConfigWithPath, BotConfigWithPathImpl } from '@bfemulator/sdk-shared'; import { BotConfiguration } from 'botframework-config'; @@ -43,6 +42,7 @@ import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shar import * as BotActions from './state/actions/botActions'; import { store } from './state/store'; import { CredentialManager } from './credentialManager'; +import { Conversation } from './server/state/conversation'; export class BotHelpers { @CommandServiceInstance() diff --git a/packages/app/main/src/commands/botCommands.spec.ts b/packages/app/main/src/commands/botCommands.spec.ts index edff4816f..5075384d0 100644 --- a/packages/app/main/src/commands/botCommands.spec.ts +++ b/packages/app/main/src/commands/botCommands.spec.ts @@ -120,15 +120,11 @@ jest.mock('../utils/ensureStoragePath', () => ({ ensureStoragePath: () => '', })); const mockEmulator = { - framework: { - server: { - botEmulator: { - facilities: { - endpoints: { - reset: () => null, - push: () => null, - }, - }, + server: { + state: { + endpoints: { + clear: jest.fn(), + set: jest.fn(), }, }, }, @@ -254,13 +250,13 @@ describe('The botCommands', () => { it('should restart the endpoint service', async () => { const emulator = Emulator.getInstance(); store.dispatch(setActive(mockBot)); - const resetSpy = jest.spyOn(emulator.framework.server.botEmulator.facilities.endpoints, 'reset'); - const pushSpy = jest.spyOn(emulator.framework.server.botEmulator.facilities.endpoints, 'push'); + const clearSpy = jest.spyOn(emulator.server.state.endpoints, 'clear'); + const setSpy = jest.spyOn(emulator.server.state.endpoints, 'set'); const command = registry.getCommand(Bot.RestartEndpointService); const result = await command(); - expect(resetSpy).toHaveBeenCalled(); - expect(pushSpy).toHaveBeenCalled(); + expect(clearSpy).toHaveBeenCalled(); + expect(setSpy).toHaveBeenCalled(); expect(result).toBeUndefined(); }); diff --git a/packages/app/main/src/commands/botCommands.ts b/packages/app/main/src/commands/botCommands.ts index 44af32d4b..a9b207a47 100644 --- a/packages/app/main/src/commands/botCommands.ts +++ b/packages/app/main/src/commands/botCommands.ts @@ -178,8 +178,8 @@ export class BotCommands { @Command(Bot.RestartEndpointService) protected async restartEndpointService() { const bot = BotHelpers.getActiveBot(); - - Emulator.getInstance().framework.server.botEmulator.facilities.endpoints.reset(); + const emulator = Emulator.getInstance(); + emulator.server.state.endpoints.clear(); const overridesArePresent = bot.overrides && bot.overrides.endpoint; let appliedOverrides = false; @@ -201,7 +201,7 @@ export class BotCommands { } } - Emulator.getInstance().framework.server.botEmulator.facilities.endpoints.push(endpoint.id, { + emulator.server.state.endpoints.set(endpoint.id, { botId: endpoint.id, botUrl: endpoint.endpoint, msaAppId: endpoint.appId, diff --git a/packages/app/main/src/commands/clientInitCommands.ts b/packages/app/main/src/commands/clientInitCommands.ts index 546667279..7ff08f632 100644 --- a/packages/app/main/src/commands/clientInitCommands.ts +++ b/packages/app/main/src/commands/clientInitCommands.ts @@ -42,7 +42,7 @@ import { ProtocolHandler } from '../protocolHandler'; import { dispatch, getSettings, store } from '../state/store'; import { getBotsFromDisk, getThemes } from '../utils'; import { openFileFromCommandLine } from '../utils/openFileFromCommandLine'; -import { pushClientAwareSettings, setFrameworkSettings } from '../state/actions/frameworkSettingsActions'; +import { setFrameworkSettings } from '../state/actions/frameworkSettingsActions'; import { AppMenuBuilder } from '../appMenuBuilder'; import { setAvailableThemes, rememberTheme } from '../state/actions/windowStateActions'; @@ -72,8 +72,7 @@ export class ClientInitCommands { const { framework, windowState } = store.getState().settings; dispatch(rememberTheme(windowState.theme)); dispatch(setAvailableThemes(getThemes())); - dispatch(setFrameworkSettings(framework)); - dispatch(pushClientAwareSettings()); + dispatch(setFrameworkSettings(framework)); // also calls pushClientAwareSettings(), which also starts the Emulator rest server (TODO: separate these out) // Load extensions ExtensionManagerImpl.unloadExtensions(); ExtensionManagerImpl.loadExtensions(); diff --git a/packages/app/main/src/commands/emulatorCommands.spec.ts b/packages/app/main/src/commands/emulatorCommands.spec.ts index 66b3c5bb7..13fbb4854 100644 --- a/packages/app/main/src/commands/emulatorCommands.spec.ts +++ b/packages/app/main/src/commands/emulatorCommands.spec.ts @@ -45,7 +45,6 @@ import { } from '@bfemulator/sdk-shared'; import { BotConfiguration } from 'botframework-config'; import { newBot, newEndpoint, SharedConstants, ValueTypesMask } from '@bfemulator/app-shared'; -import { Conversation } from '@bfemulator/emulator-core'; import { store } from '../state/store'; import * as utils from '../utils'; @@ -57,6 +56,7 @@ import { setCurrentUser } from '../state/actions/userActions'; import { pushClientAwareSettings } from '../state/actions/frameworkSettingsActions'; import { azureLoggedInUserChanged } from '../state/actions/azureAuthActions'; import { CredentialManager } from '../credentialManager'; +import { Conversation } from '../server/state/conversation'; import { EmulatorCommands } from './emulatorCommands'; @@ -146,34 +146,30 @@ jest.mock('../utils/ensureStoragePath', () => ({ let mockUsers; const mockEmulator = { startup: () => ({}), - framework: { - server: { - botEmulator: { - facilities: { - logger: { - logActivity: () => true, - logMessage: () => true, - }, - conversations: { - conversationById: () => mockConversation, - newConversation: (...args: any[]) => - new mockConversationConstructor(args[0], args[1], args[3], args[2], 'livechat'), - deleteConversation: () => true, - }, - endpoints: { - reset: () => null, - push: () => null, - }, - get users() { - return mockUsers; - }, - set users(users: any) { - mockUsers = users; - }, - }, - getServiceUrl: () => 'http://localhost:6728', + server: { + logger: { + logActivity: () => true, + logMessage: () => true, + }, + state: { + conversations: { + conversationById: () => mockConversation, + newConversation: (...args: any[]) => + new mockConversationConstructor(args[0], args[1], args[3], args[2], 'livechat'), + deleteConversation: () => true, + }, + endpoints: { + reset: () => null, + push: () => null, + }, + get users() { + return mockUsers; + }, + set users(users: any) { + mockUsers = users; }, }, + getServiceUrl: () => 'http://localhost:6728', }, ngrok: { getServiceUrl: () => 'http://localhost:5678', @@ -230,8 +226,8 @@ const mockInfo = { chatsPath: mockNormalize('Users/blerg/Documents/testbot/dialogs'), }; -const mockConversation = mockEmulator.framework.server.botEmulator.facilities.conversations.newConversation( - mockEmulator.framework.server.botEmulator, +const mockConversation = mockEmulator.server.state.conversations.newConversation( + mockEmulator.server, null, { id: '1234', name: 'User' }, '1234' @@ -468,7 +464,7 @@ describe('The emulatorCommands', () => { const getActiveBotSpy = jest.spyOn(BotHelpers, 'getActiveBot').mockReturnValue(mockBot); const conversationByIdSpy = jest - .spyOn(mockEmulator.framework.server.botEmulator.facilities.conversations, 'conversationById') + .spyOn(mockEmulator.server.state.conversations, 'conversationById') .mockReturnValue(mockConversation); const showSaveDialogSpy = jest.spyOn((utils as any).default, 'showSaveDialog').mockReturnValue('chosen/path'); @@ -566,10 +562,7 @@ describe('The emulatorCommands', () => { }); it('should delete a conversation', () => { - const deleteSpy = jest.spyOn( - mockEmulator.framework.server.botEmulator.facilities.conversations, - 'deleteConversation' - ); + const deleteSpy = jest.spyOn(mockEmulator.server.state.conversations, 'deleteConversation'); registry.getCommand(SharedConstants.Commands.Emulator.DeleteConversation)('convo1'); expect(deleteSpy).toHaveBeenCalledWith('convo1'); }); diff --git a/packages/app/main/src/commands/emulatorCommands.ts b/packages/app/main/src/commands/emulatorCommands.ts index 8c212bf89..02845eafa 100644 --- a/packages/app/main/src/commands/emulatorCommands.ts +++ b/packages/app/main/src/commands/emulatorCommands.ts @@ -34,7 +34,6 @@ import * as path from 'path'; import { newBot, newEndpoint, SharedConstants } from '@bfemulator/app-shared'; -import { Conversation, Users } from '@bfemulator/emulator-core'; import { BotConfigWithPath, Command, @@ -61,6 +60,8 @@ import { ProtocolHandler } from '../protocolHandler'; import { CredentialManager } from '../credentialManager'; import { getCurrentConversationId } from '../state/helpers/chatHelpers'; import { getLocalhostServiceUrl } from '../utils/getLocalhostServiceUrl'; +import { Conversation } from '../server/state/conversation'; +import { Users } from '../server/state/users'; const Commands = SharedConstants.Commands.Emulator; @@ -73,9 +74,7 @@ export class EmulatorCommands { @Command(Commands.SaveTranscriptToFile) protected async saveTranscriptToFile(valueTypes: number, conversationId: string): Promise { const activeBot: BotConfigWithPath = BotHelpers.getActiveBot(); - const conversation = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById( - conversationId - ); + const conversation = Emulator.getInstance().server.state.conversations.conversationById(conversationId); if (!conversation) { throw new Error(`${Commands.SaveTranscriptToFile}: Conversation ${conversationId} not found.`); } @@ -163,9 +162,7 @@ export class EmulatorCommands { throw new Error('emulator:feed-transcript:deep-link: No active bot.'); } - const convo = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById( - conversationId - ); + const convo = Emulator.getInstance().server.state.conversations.conversationById(conversationId); if (!convo) { throw new Error(`emulator:feed-transcript:deep-link: Conversation ${conversationId} not found.`); } @@ -178,7 +175,7 @@ export class EmulatorCommands { // Get a speech token @Command(Commands.GetSpeechToken) protected getSpeechToken(endpointId: string, refresh: boolean) { - const endpoint = Emulator.getInstance().framework.server.botEmulator.facilities.endpoints.get(endpointId); + const endpoint = Emulator.getInstance().server.state.endpoints.get(endpointId); return endpoint && endpoint.getSpeechToken(refresh); } @@ -197,8 +194,8 @@ export class EmulatorCommands { } const emulator = Emulator.getInstance(); // TODO: Move away from the .users state on legacy emulator settings, and towards per-conversation users - return emulator.framework.server.botEmulator.facilities.conversations.newConversation( - emulator.framework.server.botEmulator, + return emulator.server.state.conversations.newConversation( + emulator.server, null, { id: getSettings().users.currentUserId, name: 'User' }, conversationId @@ -223,12 +220,12 @@ export class EmulatorCommands { // Sets the current user id (in memory) @Command(Commands.SetCurrentUser) protected async setCurrentUser(userId: string) { - const { facilities } = Emulator.getInstance().framework.server.botEmulator; - const { users } = facilities; + const emulator = Emulator.getInstance(); + const { users } = emulator.server.state; const user = { id: userId, name: 'User' }; users.currentUserId = userId; users.users[userId] = user; - facilities.users = users; + emulator.server.state.users = users; // update the settings state on both main and client dispatch(setCurrentUser(user)); @@ -239,18 +236,14 @@ export class EmulatorCommands { // Removes the conversation from the conversation set @Command(Commands.DeleteConversation) protected deleteConversation(conversationId: string) { - return Emulator.getInstance().framework.server.botEmulator.facilities.conversations.deleteConversation( - conversationId - ); + return Emulator.getInstance().server.state.conversations.deleteConversation(conversationId); } // --------------------------------------------------------------------------- // Removes the conversation from the conversation set @Command(Commands.PostActivityToConversation) protected postActivityToConversation(conversationId: string, activity: any, toUser: boolean) { - const conversation = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById( - conversationId - ); + const conversation = Emulator.getInstance().server.state.conversations.conversationById(conversationId); if (toUser) { return conversation.postActivityToUser(activity, false); } else { @@ -261,19 +254,18 @@ export class EmulatorCommands { @Command(Commands.StartEmulator) protected async startEmulator(forceRestart: boolean = false) { const emulator = Emulator.getInstance(); - const port = emulator.framework.serverPort || null; - if (!forceRestart && emulator.framework.serverPort === port) { + if (!forceRestart && !!emulator.server.serverPort) { return; } - await emulator.startup(port); + await emulator.startup(); const { users: userSettings, framework } = getSettings(); const users = new Users(); users.currentUserId = userSettings.currentUserId; users.users = userSettings.usersById; - const { facilities } = emulator.framework.server.botEmulator; - facilities.locale = framework.locale; - facilities.users = users; + const { state } = emulator.server; + state.locale = framework.locale; + state.users = users; } @Command(Commands.OpenProtocolUrls) diff --git a/packages/app/main/src/commands/oauthCommands.ts b/packages/app/main/src/commands/oauthCommands.ts index 641e3b3ea..e53f63639 100644 --- a/packages/app/main/src/commands/oauthCommands.ts +++ b/packages/app/main/src/commands/oauthCommands.ts @@ -45,9 +45,7 @@ export class OauthCommands { // Sends an OAuth TokenResponse @Command(Commands.SendTokenResponse) protected async sendTokenResponse(connectionName: string, conversationId: string, token: string) { - const convo = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById( - conversationId - ); + const convo = Emulator.getInstance().server.state.conversations.conversationById(conversationId); if (!convo) { throw new Error(`oauth:send-token-response: Conversation ${conversationId} not found.`); } @@ -58,9 +56,7 @@ export class OauthCommands { // Opens an OAuth login window @Command(Commands.CreateOAuthWindow) protected async createOauthWindow(url: string, conversationId: string) { - const convo = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById( - conversationId - ); + const convo = Emulator.getInstance().server.state.conversations.conversationById(conversationId); emulatorApplication.windowManager.createOAuthWindow(url, convo.codeVerifier); } } diff --git a/packages/app/main/src/emulator.ts b/packages/app/main/src/emulator.ts index 92f7a071c..0e63c4fda 100644 --- a/packages/app/main/src/emulator.ts +++ b/packages/app/main/src/emulator.ts @@ -31,36 +31,66 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { BotFrameworkService } from './botFrameworkService'; import { NgrokService } from './ngrokService'; +import { defaultRestServerOptions, EmulatorRestServer, EmulatorRestServerOptions } from './server/restServer'; let emulator: Emulator; -class SingletonEnforcer {} /** * Top-level state container for the Node process. */ export class Emulator { - public ngrok = new NgrokService(); - public framework = new BotFrameworkService(); + public ngrok: NgrokService; + private _server: EmulatorRestServer; - private constructor(enforcer: SingletonEnforcer) { - if (!(enforcer instanceof SingletonEnforcer)) { - throw new Error('Emulator is a singleton. Please use Emulator.getInstance()'); + private constructor() { + this.ngrok = new NgrokService(); + } + + public static initialize(): void { + if (!emulator) { + emulator = new Emulator(); + } + } + + public static getInstance(): Emulator { + if (!emulator) { + throw new Error( + 'Emulator has not been initialized yet. Please instantiate a new instance of Emulator before calling getInstance()' + ); } + return emulator; } - public static getInstance() { - return emulator || (emulator = new Emulator(new SingletonEnforcer())); + public get server(): EmulatorRestServer { + if (!this._server) { + throw new Error('Emulator rest server has not been initialized yet. Please call initServer().'); + } + return this._server; } + + /** Initializes the emulator rest server. No-op if already called. */ + public initServer(options: EmulatorRestServerOptions = defaultRestServerOptions): void { + if (!this._server) { + this._server = new EmulatorRestServer({ + ...options, + getServiceUrl: botUrl => this.ngrok.getServiceUrl(botUrl), + getServiceUrlForOAuth: () => this.ngrok.getServiceUrlForOAuth(), + shutDownOAuthNgrokInstance: () => this.ngrok.shutDownOAuthNgrokInstance(), + }); + } + } + /** - * Loads settings from disk and then creates the emulator. + * Starts the rest server and mounts all the routes. + * @param port Explicit port that the server will listen on. + * Omitting the port will automatically choose a free port. */ - public async startup(port) { - await this.framework.recycle(port); + public async startup(port?: number) { + await this.server.start(port); } public async report(conversationId: string, botUrl: string): Promise { - this.framework.report(conversationId); + this.server.report(conversationId); await this.ngrok.report(conversationId, botUrl); } } diff --git a/packages/app/main/src/main.ts b/packages/app/main/src/main.ts index 7372b5acf..b285183a5 100644 --- a/packages/app/main/src/main.ts +++ b/packages/app/main/src/main.ts @@ -137,6 +137,7 @@ class EmulatorApplication { private fileToOpen: string; constructor() { + Emulator.initialize(); this.initializeNgrokListeners(); this.initializeAppListeners(); this.initializeSystemPreferencesListeners(); @@ -285,6 +286,7 @@ class EmulatorApplication { this.initializeBrowserWindowListeners(); this.mainWindow = new Window(this.mainBrowserWindow); + Emulator.getInstance().initServer({ fetch, logService: this.mainWindow.logService }); if (process.env.NODE_ENV !== 'test') { SplashScreen.show(this.mainBrowserWindow); diff --git a/packages/app/main/src/ngrokService.spec.ts b/packages/app/main/src/ngrokService.spec.ts index e0aeb5c13..6480c8152 100644 --- a/packages/app/main/src/ngrokService.spec.ts +++ b/packages/app/main/src/ngrokService.spec.ts @@ -30,34 +30,26 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // + import { SettingsImpl } from '@bfemulator/app-shared'; import { combineReducers, createStore } from 'redux'; -import { bot } from './state/reducers/bot'; -import { Emulator } from './emulator'; import { NgrokService } from './ngrokService'; import { setFrameworkSettings } from './state/actions/frameworkSettingsActions'; import { azureAuthSettings, framework, savedBotUrls, windowState, users } from './state/reducers'; import { store } from './state/store'; const mockEmulator = { - framework: { + server: { serverUrl: 'http://localhost:3000', - locale: 'en-us', - bypassNgrokLocalhost: true, serverPort: 8080, - ngrokPath: '/usr/bin/ngrok', - server: { - botEmulator: { - facilities: { - conversations: { - getConversationIds: () => ['12', '123'], - }, - endpoints: { - reset: () => null, - push: () => null, - }, - }, + state: { + conversations: { + getConversationIds: () => ['12', '123'], + }, + endpoints: { + reset: () => null, + push: () => null, }, }, }, @@ -123,9 +115,14 @@ jest.mock('./ngrok', () => { describe('The ngrokService', () => { const ngrokService = new NgrokService(); + const settings = { + locale: 'en-us', + bypassNgrokLocalhost: true, + ngrokPath: '/usr/bin/ngrok', + }; beforeEach(() => { - store.dispatch(setFrameworkSettings(Emulator.getInstance().framework as any)); + store.dispatch(setFrameworkSettings(settings as any)); mockCallsToLog.length = 0; mockRunning.mockClear(); mockConnect.mockClear(); diff --git a/packages/app/main/src/ngrokService.ts b/packages/app/main/src/ngrokService.ts index 864146eb4..53b5a3eed 100644 --- a/packages/app/main/src/ngrokService.ts +++ b/packages/app/main/src/ngrokService.ts @@ -89,7 +89,7 @@ export class NgrokService { return this.serviceUrl; } // Do not use ngrok - return `http://${this.localhost}:${Emulator.getInstance().framework.serverPort}`; + return `http://${this.localhost}:${Emulator.getInstance().server.serverPort}`; } // OAuth sign-in flow must always use an ngrok url so that the BF token @@ -104,7 +104,7 @@ export class NgrokService { } // otherwise, we need to spin up an auxillary ngrok instance that we can tear down when the token response comes back this.oauthNgrokInstance = new NgrokInstance(); - const port = Emulator.getInstance().framework.serverPort; + const port = Emulator.getInstance().server.serverPort; const ngrokPath = getSettings().framework.ngrokPath; const inspectUrl = new Promise(async (resolve, reject) => { try { @@ -145,7 +145,7 @@ export class NgrokService { } this.ngrok.kill(); - const port = Emulator.getInstance().framework.serverPort; + const port = Emulator.getInstance().server.serverPort; this.ngrokPath = getSettings().framework.ngrokPath; this.serviceUrl = `http://${this.localhost}:${port}`; @@ -211,7 +211,7 @@ export class NgrokService { /** Logs an item to all open conversations */ public broadcast(...logItems: LogItem[]): void { - const { conversations } = Emulator.getInstance().framework.server.botEmulator.facilities; + const { conversations } = Emulator.getInstance().server.state; const conversationIds: string[] = conversations.getConversationIds(); conversationIds.forEach(id => { emulatorApplication.mainWindow.logService.logToChat(id, ...logItems); @@ -287,6 +287,11 @@ export class NgrokService { // Get framework from state const framework = getSettings().framework; + // ensure that a path to ngrok gets set initially + if (!this.ngrokPath && framework.ngrokPath) { + this.ngrokPath = framework.ngrokPath; + } + // Cache host and port const localhost = framework.localhost || 'localhost'; const parts = localhost.split(':'); diff --git a/packages/app/main/src/restServer.spec.ts b/packages/app/main/src/restServer.spec.ts deleted file mode 100644 index b21543607..000000000 --- a/packages/app/main/src/restServer.spec.ts +++ /dev/null @@ -1,195 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared'; - -import { Emulator } from './emulator'; -import './fetchProxy'; -import { emulatorApplication } from './main'; -import { RestServer } from './restServer'; - -jest.mock('./main', () => ({ - emulatorApplication: { - mainWindow: { - logService: { - logToChat: () => void 0, - }, - }, - }, -})); -const mockEmulator = { - report() { - return null; - }, -}; - -jest.mock('electron', () => ({ - ipcMain: new Proxy( - {}, - { - get(): any { - return () => ({}); - }, - has() { - return true; - }, - } - ), - ipcRenderer: new Proxy( - {}, - { - get(): any { - return () => ({}); - }, - has() { - return true; - }, - } - ), -})); - -jest.mock('./emulator', () => ({ - Emulator: { - getInstance: () => { - return mockEmulator; - }, - }, -})); - -describe('The restServer', () => { - let commandService: CommandServiceImpl; - let restServer; - beforeAll(() => { - const decorator = CommandServiceInstance(); - const descriptor = decorator({ descriptor: {} }, 'none') as any; - commandService = descriptor.descriptor.get(); - restServer = new RestServer(); - }); - - it('should log to the LOG panel after each successful request', () => { - const logSpy = jest.spyOn(emulatorApplication.mainWindow.logService, 'logToChat'); - const mockReq = { - method: 'post', - conversation: { - conversationId: '123', - }, - params: {}, - _body: {}, - headers: {}, - url: 'http://localhost', - statusCode: 200, - statusMessage: 'ok', - }; - const mockRes = { - statusCode: 200, - }; - const mockRoute = { - spec: { path: '' }, - }; - (restServer as any).onRouterAfter(mockReq, mockRes, mockRoute); - - expect(logSpy).toHaveBeenCalledWith( - '123', - { - payload: { - body: {}, - facility: 'network', - headers: {}, - method: 'post', - url: 'http://localhost', - }, - type: 'network-request', - }, - { - payload: { - body: undefined, - headers: undefined, - srcUrl: 'http://localhost', - statusCode: 200, - statusMessage: undefined, - }, - type: 'network-response', - }, - { payload: { level: 0, text: 'network.' }, type: 'text' } - ); - }); - - it('should create a new conversation and open a new livechat window', async () => { - const remoteCallSpy = jest.spyOn(commandService, 'remoteCall').mockResolvedValue(true); - const reportSpy = jest.spyOn(Emulator.getInstance(), 'report'); - const mockConversation = { - conversationId: '123', - botEndpoint: { id: '456', url: 'https://localhost' }, - mode: 'livechat', - }; - await (restServer as any).onNewConversation(mockConversation); - expect(remoteCallSpy).toHaveBeenCalledWith( - 'livechat:new', - { - endpoint: undefined, - id: '456', - }, - false, - '123', - 'livechat' - ); - expect(reportSpy).toHaveBeenCalledWith('123', undefined); - - remoteCallSpy.mockReset(); - reportSpy.mockReset(); - }); - - it('should not create a new conversation when the conversationId contains "transcript"', async () => { - const remoteCallSpy = jest.spyOn(commandService, 'remoteCall').mockResolvedValue(true); - const reportSpy = jest.spyOn(Emulator.getInstance(), 'report'); - const mockConversation = { - conversationId: 'transcript', - botEndpoint: { id: '456', url: 'https://localhost' }, - }; - await (restServer as any).onNewConversation(mockConversation); - expect(remoteCallSpy).not.toHaveBeenCalled(); - expect(reportSpy).not.toHaveBeenCalled(); - }); - - it('should begin listening when listen is called', async () => { - const result = await restServer.listen(); - expect(result).toEqual({ - url: jasmine.any(String), - port: jasmine.any(Number), - }); - }); - - it('should close the server when close is called', async () => { - const result = await restServer.close(); - expect(result).toBeUndefined(); - }); -}); diff --git a/packages/app/main/src/restServer.ts b/packages/app/main/src/restServer.ts deleted file mode 100644 index 1acbbdbed..000000000 --- a/packages/app/main/src/restServer.ts +++ /dev/null @@ -1,196 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { SharedConstants } from '@bfemulator/app-shared'; -import { BotEmulator, Conversation, ConversationSet } from '@bfemulator/emulator-core'; -import { LogLevel, networkRequestItem, networkResponseItem, textItem } from '@bfemulator/sdk-shared'; -import { IEndpointService } from 'botframework-config'; -import { createServer, Request, Response, Route, Server } from 'restify'; -import CORS from 'restify-cors-middleware'; -import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared'; - -import { Emulator } from './emulator'; -import { emulatorApplication } from './main'; - -interface ConversationAwareRequest extends Request { - conversation?: { conversationId?: string }; - params?: { conversationId?: string }; -} - -export class RestServer { - @CommandServiceInstance() - private commandService: CommandServiceImpl; - private readonly router: Server; - - // Late binding - private _botEmulator: BotEmulator; - public get botEmulator(): BotEmulator { - if (!this._botEmulator) { - this._botEmulator = new BotEmulator( - botUrl => Emulator.getInstance().ngrok.getServiceUrl(botUrl), - () => Emulator.getInstance().ngrok.getServiceUrlForOAuth(), - () => Emulator.getInstance().ngrok.shutDownOAuthNgrokInstance(), - { - fetch, - loggerOrLogService: emulatorApplication.mainWindow.logService, - } - ); - this._botEmulator.facilities.conversations.on('new', this.onNewConversation); - } - return this._botEmulator; - } - - constructor() { - const cors = CORS({ - origins: ['*'], - allowHeaders: [ - 'authorization', - 'x-requested-with', - 'x-ms-bot-agent', - 'x-emulator-appid', - 'x-emulator-apppassword', - 'x-emulator-botendpoint', - 'x-emulator-channelservice', - ], - exposeHeaders: [], - }); - - const router = createServer({ - name: 'Emulator', - }); - - router.on('after', this.onRouterAfter); - router.pre(cors.preflight); - router.use(cors.actual); - - this.router = router; - } - - public listen(port?: number): Promise<{ url: string; port: number }> { - return new Promise((resolve, reject) => { - this.router.once('error', err => reject(err)); - this.router.listen(port, () => { - this.botEmulator.mount(this.router as any); - resolve({ url: this.router.url, port: this.router.address().port }); - }); - }); - } - - public close() { - return new Promise(resolve => { - if (this.router) { - this.router.close(() => resolve()); - } else { - resolve(); - } - }); - } - - private onRouterAfter = async (req: Request, res: Response, route: Route) => { - const conversationId = getConversationId(req as ConversationAwareRequest); - if (!shouldPostToChat(conversationId, req.method, route, req as any)) { - return; - } - - const facility = (req as any).facility || 'network'; - const routeName = (req as any).routeName || ''; - - let level = LogLevel.Debug; - if (!/2\d\d/.test(res.statusCode.toString())) { - level = LogLevel.Error; - } - - let responseHeaders; - try { - responseHeaders = res.headers(); - } catch (e) { - responseHeaders = undefined; - } - - emulatorApplication.mainWindow.logService.logToChat( - conversationId, - networkRequestItem(facility, (req as any)._body, req.headers, req.method, req.url), - networkResponseItem((res as any)._data, responseHeaders, res.statusCode, res.statusMessage, req.url), - textItem(level, `${facility}.${routeName}`) - ); - }; - - private onNewConversation = async (conversation: Conversation = {} as Conversation) => { - const { conversationId = '' } = conversation; - if (!conversationId || conversationId.includes('transcript')) { - return; - } - // Check for an existing livechat window - // before creating a new one since "new" - // can also mean "restart". - const { - botEndpoint: { id, botUrl }, - mode, - } = conversation; - - await this.commandService.remoteCall( - SharedConstants.Commands.Emulator.NewLiveChat, - { - id, - endpoint: botUrl, - } as IEndpointService, - hasLiveChat(conversationId, this.botEmulator.facilities.conversations), - conversationId, - mode - ); - await Emulator.getInstance().report(conversationId, botUrl); - }; -} - -function shouldPostToChat( - conversationId: string, - method: string, - route: Route, - req: { body: {}; conversation: Conversation } -): boolean { - const isDLine = method === 'GET' && route.spec.path === '/v3/directline/conversations/:conversationId/activities'; - const isNotTranscript = !!conversationId && !conversationId.includes('transcript'); - const { conversation } = req; - return !isDLine && isNotTranscript && conversation && conversation.mode !== 'debug'; -} - -function getConversationId(req: ConversationAwareRequest): string { - return req.conversation ? req.conversation.conversationId : req.params.conversationId; -} - -function hasLiveChat(conversationId: string, conversationSet: ConversationSet): boolean { - if (conversationId.endsWith('|livechat')) { - return !!conversationSet.conversationById(conversationId); - } - return !!conversationSet.conversationById(conversationId + '|livechat'); -} diff --git a/packages/emulator/core/src/authEndpoints.ts b/packages/app/main/src/server/constants/authEndpoints.ts similarity index 100% rename from packages/emulator/core/src/authEndpoints.ts rename to packages/app/main/src/server/constants/authEndpoints.ts diff --git a/packages/app/main/src/server/restServer.ts b/packages/app/main/src/server/restServer.ts new file mode 100644 index 000000000..a24bb7cc5 --- /dev/null +++ b/packages/app/main/src/server/restServer.ts @@ -0,0 +1,289 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { + LogService, + LogLevel, + CommandServiceImpl, + CommandServiceInstance, + textItem, + Logger, + networkRequestItem, + networkResponseItem, +} from '@bfemulator/sdk-shared'; +import { createServer, plugins, Server, Response, Route } from 'restify'; +import CORS from 'restify-cors-middleware'; +import { newNotification, SharedConstants } from '@bfemulator/app-shared'; +import { IEndpointService } from 'botframework-config/lib/schema'; + +import { Emulator } from '../emulator'; + +import { mountAllRoutes } from './routes/mountAllRoutes'; +import { ServerState } from './state/serverState'; +import { LoggerAdapter } from './state/loggerAdapter'; +import { ConsoleLogService } from './state/consoleLogService'; +import { stripEmptyBearerTokenMiddleware } from './routes/handlers/stripEmptyBearerToken'; +import { Conversation } from './state/conversation'; +import { ConversationSet } from './state/conversationSet'; + +export interface EmulatorRestServerOptions { + fetch?: (url: string, options?: any) => Promise; + getServiceUrl?: (botUrl: string) => Promise; + getServiceUrlForOAuth?: () => Promise; + logService?: LogService; + shutDownOAuthNgrokInstance?: () => void; +} + +export const defaultRestServerOptions: EmulatorRestServerOptions = { + fetch: undefined, + getServiceUrl: () => + new Promise((_, reject) => + reject( + new Error( + 'getServiceUrl() has not been configured. Please configure this function by passing it into the EmulatorRestServer constructor via the "options" object.' + ) + ) + ), + getServiceUrlForOAuth: () => + new Promise((_, reject) => + reject( + new Error( + 'getServiceUrlForOAuth() has not been configured. Please configure this function by passing it into the EmulatorRestServer constructor via the "options" object.' + ) + ) + ), + logService: new ConsoleLogService(), + shutDownOAuthNgrokInstance: () => + new Error( + 'shutdownOAuthNgrokInstance() has not been configured. Please configure this function by passing it into the EmulatorRestServer constructor via the "options" object.' + ), +}; + +interface ConversationAwareRequest extends Request { + conversation?: { conversationId?: string }; + params?: { conversationId?: string }; +} + +const cors = CORS({ + origins: ['*'], + allowHeaders: [ + 'authorization', + 'x-requested-with', + 'x-ms-bot-agent', + 'x-emulator-appid', + 'x-emulator-apppassword', + 'x-emulator-botendpoint', + 'x-emulator-channelservice', + ], + exposeHeaders: [], +}); + +let server; +export class EmulatorRestServer { + @CommandServiceInstance() + private commandService: CommandServiceImpl; + private _serverPort: number; + private _serverUrl: string; + public getServiceUrl: (botUrl: string) => Promise; + public getServiceUrlForOAuth: () => Promise; + public logger: Logger; + public options: EmulatorRestServerOptions; + public server: Server; + public shutDownOAuthNgrokInstance: () => void; + public state: ServerState; + + public get serverPort(): number { + return this._serverPort; + } + + public get serverUrl(): string { + return this._serverUrl; + } + + constructor(options: EmulatorRestServerOptions) { + // singleton + if (server) { + return server; + } + this.options = { + ...defaultRestServerOptions, + ...options, + }; + this.logger = new LoggerAdapter(this.options.logService); + this.state = new ServerState(this.options.fetch); + this.state.conversations.on('new', this.onNewConversation); + this.getServiceUrl = this.options.getServiceUrl; + this.getServiceUrlForOAuth = this.options.getServiceUrlForOAuth; + this.shutDownOAuthNgrokInstance = this.options.shutDownOAuthNgrokInstance; + return (server = this); + } + + public async start(port?: number): Promise { + if (this.server) { + this.server.close(); + } + try { + await this.createServer(); + // start listening + const actualPort = await new Promise((resolve, reject) => { + this.server.once('error', err => reject(err)); + this.server.listen(port, () => { + resolve(this.server.address().port); + }); + }); + mountAllRoutes(this); + this._serverPort = actualPort; + this._serverUrl = this.server.url; + } catch (e) { + if (e.code === 'EADDRINUSE') { + // eslint-disable-next-line + console.error('Address already in use: ', e); + + const notification = newNotification( + `Port ${port} is in use and the Emulator cannot start. Please free this port so the emulator can use it.` + ); + await this.commandService.remoteCall(SharedConstants.Commands.Notifications.Add, notification); + } + } + } + + public close(): Promise { + return new Promise(resolve => { + if (this.server) { + this.server.close(resolve); + } else { + resolve(); + } + }); + } + + public report(conversationId: string): void { + this.options.logService.logToChat( + conversationId, + textItem(LogLevel.Debug, `Emulator listening on ${this.serverUrl}`) + ); + } + + private async createServer(): Promise { + const server = createServer({ name: 'Emulator' }); + server.on('after', this.onAfterRequest); + server.pre(cors.preflight); + server.use([ + cors.actual, + plugins.acceptParser(server.acceptable), + stripEmptyBearerTokenMiddleware, // keep an eye on this; this and below handlers were only being used on some routes + plugins.dateParser(), + plugins.queryParser(), + ]); + this.server = server; + } + + private onAfterRequest = (req: Request, res: Response, route: Route, err): void => { + const conversationId = getConversationId(req as ConversationAwareRequest); // route.spec.path: '/api/userToken/getUserData + if (!shouldPostToChat(conversationId, req.method, route, req as any)) { + return; + } + + let level = LogLevel.Debug; + if (!/2\d\d/.test(res.statusCode.toString())) { + level = LogLevel.Error; + } + + // /api/conversation/activities => [api, conversation, activities] + const routeSegments = ((route.spec.path as string) || '').split('/').filter(segment => !!segment); + + this.options.logService.logToChat( + conversationId, + networkRequestItem( + routeSegments[1] || 'N/A' /* TODO: something else here instea of N/A? */, + (req as any)._body, + req.headers, + req.method, + req.url + ), + networkResponseItem((res as any)._data, res.headers, res.statusCode, res.statusMessage, req.url), + textItem(level, routeSegments.slice(1).join('.')) + ); + }; + + private onNewConversation = async (conversation: Conversation = {} as Conversation) => { + const { conversationId = '' } = conversation; + if (!conversationId || conversationId.includes('transcript')) { + return; + } + // Check for an existing livechat window + // before creating a new one since "new" + // can also mean "restart". + const { + botEndpoint: { id, botUrl }, + mode, + } = conversation; + + await this.commandService.remoteCall( + SharedConstants.Commands.Emulator.NewLiveChat, + { + id, + endpoint: botUrl, + } as IEndpointService, + // replace this with some other logic that doesn't use this.botEmulator + hasLiveChat(conversationId, this.state.conversations), + conversationId, + mode + ); + this.report(conversationId); + Emulator.getInstance().ngrok.report(conversationId, botUrl); + }; +} + +function shouldPostToChat( + conversationId: string, + method: string, + route: Route, + req: { body: {}; conversation: Conversation } +): boolean { + const isDLine = method === 'GET' && route.spec.path === '/v3/directline/conversations/:conversationId/activities'; + const isNotTranscript = !!conversationId && !conversationId.includes('transcript'); + const { conversation } = req; + return !isDLine && isNotTranscript && conversation && conversation.mode !== 'debug'; +} + +function getConversationId(req: ConversationAwareRequest): string { + return req.conversation ? req.conversation.conversationId : req.params.conversationId; +} + +function hasLiveChat(conversationId: string, conversationSet: ConversationSet): boolean { + if (conversationId.endsWith('|livechat')) { + return !!conversationSet.conversationById(conversationId); + } + return !!conversationSet.conversationById(conversationId + '|livechat'); +} diff --git a/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.spec.ts b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.spec.ts new file mode 100644 index 000000000..e97dd27e8 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.spec.ts @@ -0,0 +1,203 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { ErrorCodes } from '@bfemulator/app-shared'; + +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; + +import { createGetAttachmentHandler } from './getAttachment'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getAttachment handler', () => { + let state; + + beforeEach(() => { + state = {}; + mockSendErrorResponse.mockClear(); + }); + + it('should return the attachment content uploaded via Web Chat', () => { + const mockAttachmentData = new Uint8Array(Buffer.from('aGk=')); + state.attachments = { + getAttachmentData: jest.fn(() => ({ + originalBase64: mockAttachmentData, + type: 'text/plain', + })), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: { viewId: 'original' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(res.contentType).toBe('text/plain'); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, Buffer.from(mockAttachmentData)); + expect(next).toHaveBeenCalled(); + }); + + it('should return the attachment content uploaded via the bot', () => { + const mockAttachmentData = Buffer.from('some data', 'base64').toString(); + state.attachments = { + getAttachmentData: jest.fn(() => ({ + originalBase64: mockAttachmentData, + type: 'text/plain', + })), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: { viewId: 'original' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(res.contentType).toBe('text/plain'); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, Buffer.from(mockAttachmentData.toString(), 'base64')); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message if the original view is requested, but missing', () => { + state.attachments = { + getAttachmentData: jest.fn(() => ({ originalBase64: undefined })), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: { viewId: 'original' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'There is no original view') + ); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message if the thumbnail view is requested, but missing', () => { + state.attachments = { + getAttachmentData: jest.fn(() => ({ thumbnailBase64: undefined })), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: { viewId: 'thumbnail' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'There is no thumbnail view') + ); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message the attachment can not be found', () => { + state.attachments = { + getAttachmentData: jest.fn(() => undefined), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: { attachmentId: 'attach1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException( + HttpStatus.NOT_FOUND, + ErrorCodes.BadArgument, + `attachment[${req.params.attachmentId}] not found` + ) + ); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message if an error is thrown', () => { + state.attachments = { + getAttachmentData: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const getAttachmentHandler = createGetAttachmentHandler(state); + const req: any = { + params: {}, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getAttachmentHandler(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCodes.ServiceError, 'Something went wrong.') + ); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/attachments/middleware/getAttachment.ts b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.ts similarity index 77% rename from packages/emulator/core/src/attachments/middleware/getAttachment.ts rename to packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.ts index b78a8fc71..924c830c2 100644 --- a/packages/emulator/core/src/attachments/middleware/getAttachment.ts +++ b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachment.ts @@ -36,20 +36,21 @@ import { AttachmentData } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import AttachmentParams from '../attachmentParams'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; +import AttachmentParams from '../types/attachmentParams'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { ServerState } from '../../../../state/serverState'; -export default function getAttachment(bot: BotEmulator) { +export function createGetAttachmentHandler(state: ServerState) { return (req: Request, res: Response, next: Next): any => { try { - const parms: AttachmentParams = req.params; - const attachment: AttachmentData = bot.facilities.attachments.getAttachmentData(parms.attachmentId); + const params: AttachmentParams = req.params; + const attachment: AttachmentData = state.attachments.getAttachmentData(params.attachmentId); if (attachment) { - if (parms.viewId === 'original' || parms.viewId === 'thumbnail') { - const attachmentBase64 = parms.viewId === 'original' ? attachment.originalBase64 : attachment.thumbnailBase64; + if (params.viewId === 'original' || params.viewId === 'thumbnail') { + const attachmentBase64 = + params.viewId === 'original' ? attachment.originalBase64 : attachment.thumbnailBase64; if (attachmentBase64) { // can be an ArrayBuffer if uploaded via the Web Chat paperclip control, or can be @@ -71,7 +72,7 @@ export default function getAttachment(bot: BotEmulator) { createAPIException( HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, - parms.viewId === 'original' ? 'There is no original view' : 'There is no thumbnail view' + params.viewId === 'original' ? 'There is no original view' : 'There is no thumbnail view' ) ); } @@ -84,7 +85,7 @@ export default function getAttachment(bot: BotEmulator) { createAPIException( HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, - `attachment[${parms.attachmentId}] not found` + `attachment[${params.attachmentId}] not found` ) ); } diff --git a/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.spec.ts b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.spec.ts new file mode 100644 index 000000000..46b59e02b --- /dev/null +++ b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.spec.ts @@ -0,0 +1,146 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { ErrorCodes } from '@bfemulator/sdk-shared'; +import * as HttpStatus from 'http-status-codes'; + +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; + +import { createGetAttachmentInfoHandler } from './getAttachmentInfo'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getAttachmentInfo handler', () => { + let state; + + beforeEach(() => { + state = {}; + }); + + it('should return info about the attachment', () => { + const mockAttachment = { + name: 'my-attachment', + type: 'image/png', + originalBase64: new Uint8Array(Buffer.from('aGk=')), + thumbnailBase64: new Uint8Array(Buffer.from('data')), + }; + state.attachments = { + getAttachmentData: jest.fn(() => mockAttachment), + }; + const req: any = { + params: { attachmentId: 'attach1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const getAttachmentInfo = createGetAttachmentInfoHandler(state); + getAttachmentInfo(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { + name: mockAttachment.name, + type: mockAttachment.type, + views: [ + { + viewId: 'original', + size: Buffer.from(Buffer.from(mockAttachment.originalBase64.buffer as ArrayBuffer).toString(), 'base64') + .length, + }, + { + viewId: 'thumbnail', + size: Buffer.from(Buffer.from(mockAttachment.thumbnailBase64.buffer as ArrayBuffer).toString(), 'base64') + .length, + }, + ], + }); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message if the attachment is not found', () => { + state.attachments = { + getAttachmentData: jest.fn(undefined), + }; + const req: any = { + params: { attachmentId: 'attach1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const getAttachmentInfo = createGetAttachmentInfoHandler(state); + getAttachmentInfo(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException( + HttpStatus.NOT_FOUND, + ErrorCodes.BadArgument, + `attachment[${req.params.attachmentId}] not found` + ) + ); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error message if something goes wrong', () => { + state.attachments = { + getAttachmentData: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const req: any = { + params: {}, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const getAttachmentInfo = createGetAttachmentInfoHandler(state); + getAttachmentInfo(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCodes.ServiceError, 'Something went wrong.') + ); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/attachments/middleware/getAttachmentInfo.ts b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.ts similarity index 87% rename from packages/emulator/core/src/attachments/middleware/getAttachmentInfo.ts rename to packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.ts index c4e029fe3..143ae9f63 100644 --- a/packages/emulator/core/src/attachments/middleware/getAttachmentInfo.ts +++ b/packages/app/main/src/server/routes/channel/attachments/handlers/getAttachmentInfo.ts @@ -36,16 +36,16 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import AttachmentParams from '../attachmentParams'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; +import AttachmentParams from '../types/attachmentParams'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { ServerState } from '../../../../state/serverState'; -export default function getAttachmentInfo(botEmulator: BotEmulator) { +export function createGetAttachmentInfoHandler(state: ServerState) { return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { try { const parms: AttachmentParams = req.params; - const attachment: AttachmentData = botEmulator.facilities.attachments.getAttachmentData(parms.attachmentId); + const attachment: AttachmentData = state.attachments.getAttachmentData(parms.attachmentId); if (attachment) { const attachmentInfo: AttachmentInfo = { diff --git a/packages/emulator/core/src/session/registerRoutes.spec.ts b/packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.spec.ts similarity index 63% rename from packages/emulator/core/src/session/registerRoutes.spec.ts rename to packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.spec.ts index 4c5387041..5ec659153 100644 --- a/packages/emulator/core/src/session/registerRoutes.spec.ts +++ b/packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.spec.ts @@ -31,35 +31,29 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; +import { mountAttachmentsRoutes } from './mountAttachmentsRoutes'; +import { createGetAttachmentHandler } from './handlers/getAttachment'; +import { createGetAttachmentInfoHandler } from './handlers/getAttachmentInfo'; -import getSessionId from './middleware/getSessionId'; -import registerRoutes from './registerRoutes'; +jest.mock('./handlers/getAttachment', () => ({ createGetAttachmentHandler: jest.fn() })); +jest.mock('./handlers/getAttachmentInfo', () => ({ createGetAttachmentInfoHandler: jest.fn() })); -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('./middleware/getSessionId', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); +describe('mountAttachmentsRoutes', () => { + it('should mount the routes', () => { + const get = jest.fn(); const server: any = { get, }; - const uses = []; const emulator: any = { - options: { fetch: () => null }, + server, + state: {}, }; - const facility = getFacility('directline'); - registerRoutes(emulator, server, uses); + mountAttachmentsRoutes(emulator); + expect(get).toHaveBeenCalledWith('/v3/attachments/:attachmentId', createGetAttachmentInfoHandler(emulator.state)); expect(get).toHaveBeenCalledWith( - '/v3/directline/session/getsessionid', - facility, - getRouteName('getSessionId'), - getSessionId(emulator) + '/v3/attachments/:attachmentId/views/:viewId', + createGetAttachmentHandler(emulator.state) ); - expect(get).toHaveBeenCalledWith('v4/token', jasmine.any(Function)); }); }); diff --git a/packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.ts b/packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.ts new file mode 100644 index 000000000..10330a475 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/attachments/mountAttachmentsRoutes.ts @@ -0,0 +1,45 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { EmulatorRestServer } from '../../../restServer'; + +import { createGetAttachmentHandler } from './handlers/getAttachment'; +import { createGetAttachmentInfoHandler } from './handlers/getAttachmentInfo'; + +export function mountAttachmentsRoutes(emulatorServer: EmulatorRestServer) { + const { server, state } = emulatorServer; + + server.get('/v3/attachments/:attachmentId', createGetAttachmentInfoHandler(state)); + + server.get('/v3/attachments/:attachmentId/views/:viewId', createGetAttachmentHandler(state)); +} diff --git a/packages/emulator/core/src/attachments/attachmentParams.ts b/packages/app/main/src/server/routes/channel/attachments/types/attachmentParams.ts similarity index 100% rename from packages/emulator/core/src/attachments/attachmentParams.ts rename to packages/app/main/src/server/routes/channel/attachments/types/attachmentParams.ts diff --git a/packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.spec.ts b/packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.spec.ts new file mode 100644 index 000000000..d3df49253 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.spec.ts @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { sendBotStateDeprecationMessage } from './sendBotStateDeprecationMessage'; + +describe('sendBotStateDeprecationMessage', () => { + it('should send a message about the deprecation of the bot state service', () => { + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + sendBotStateDeprecationMessage(undefined, res, next); + + expect(res.end).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith( + 405, + 'The bot state service is deprectaed, see https://blog.botframework.com/2017/12/19/bot-state-service-will-soon-retired-march-31st-2018/. The bot should use its own storage.' + ); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/middleware/getFacility.ts b/packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.ts similarity index 79% rename from packages/emulator/core/src/middleware/getFacility.ts rename to packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.ts index 2fe522e1c..a895a2f60 100644 --- a/packages/emulator/core/src/middleware/getFacility.ts +++ b/packages/app/main/src/server/routes/channel/botState/handlers/sendBotStateDeprecationMessage.ts @@ -31,11 +31,13 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -export default function getFacility(facility: string) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - (req as any).facility = facility; - next(); - }; +export function sendBotStateDeprecationMessage(req: Request, res: Response, next: Next) { + res.send( + 405, + 'The bot state service is deprectaed, see https://blog.botframework.com/2017/12/19/bot-state-service-will-soon-retired-march-31st-2018/. The bot should use its own storage.' + ); + res.end(); + next(); } diff --git a/packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.spec.ts b/packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.spec.ts new file mode 100644 index 000000000..040f3f0f6 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.spec.ts @@ -0,0 +1,57 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { sendBotStateDeprecationMessage } from './handlers/sendBotStateDeprecationMessage'; +import { mountBotStateRoutes } from './mountBotStateRoutes'; + +jest.mock('./handlers/sendBotStateDeprecationMessage', () => ({ + sendBotStateDeprecationMessage: jest.fn(), +})); + +describe('mountBotStateRoutes', () => { + it('should mount the routes', () => { + const server: any = { + get: jest.fn(), + post: jest.fn(), + del: jest.fn(), + }; + const emulatorServer: any = { + server, + }; + mountBotStateRoutes(emulatorServer); + + expect(server.get).toHaveBeenCalledWith('/v3/botstate*', sendBotStateDeprecationMessage); + expect(server.post).toHaveBeenCalledWith('/v3/botstate*', sendBotStateDeprecationMessage); + expect(server.del).toHaveBeenCalledWith('/v3/botstate*', sendBotStateDeprecationMessage); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/fetchBotData.ts b/packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.ts similarity index 75% rename from packages/emulator/core/src/botState/middleware/fetchBotData.ts rename to packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.ts index f4e2555c5..743aa8100 100644 --- a/packages/emulator/core/src/botState/middleware/fetchBotData.ts +++ b/packages/app/main/src/server/routes/channel/botState/mountBotStateRoutes.ts @@ -31,18 +31,14 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import * as Restify from 'restify'; +import { EmulatorRestServer } from '../../../restServer'; -import { BotEmulator } from '../../botEmulator'; +import { sendBotStateDeprecationMessage } from './handlers/sendBotStateDeprecationMessage'; -export default function fetchBotData(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - (req as any).botData = botEmulator.facilities.botState.getBotData( - req.params.channelId, - req.params.conversationId, - req.params.userId - ); +export function mountBotStateRoutes(emulatorServer: EmulatorRestServer) { + const { server } = emulatorServer; - return next(); - }; + server.get('/v3/botstate*', sendBotStateDeprecationMessage); + server.post('/v3/botstate*', sendBotStateDeprecationMessage); + server.del('/v3/botstate*', sendBotStateDeprecationMessage); } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.spec.ts new file mode 100644 index 000000000..c3420f0ac --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.spec.ts @@ -0,0 +1,109 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createCreateConversationHandler } from './createConversation'; +import * as validateCreateConversationRequest from './errorCondition/createConversationValidator'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('createConversation handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with a create conversation response when the conversation does not exist', () => { + const validateCreateConversationRequestSpy = jest + .spyOn(validateCreateConversationRequest, 'validateCreateConversationRequest') + .mockImplementation(() => false as any); + const mockNewConversation = { + conversationId: 'convo1', + normalize: jest.fn(), + }; + const emulatorServer: any = { + postActivityToUser: jest.fn(() => ({ id: 'activity1' })), + state: { + conversations: { + conversationById: jest.fn(() => undefined), + newConversation: jest.fn(() => mockNewConversation), + }, + users: { + currentUserId: 'user1', + }, + }, + }; + const createConversation = createCreateConversationHandler(emulatorServer); + const req: any = { + body: { + conversationId: 'convo1', + members: [{ id: 'member1' }], + mode: 'livechat', + }, + botEndpoint: { botId: 'bot1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + createConversation(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { id: 'convo1' }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + + validateCreateConversationRequestSpy.mockRestore(); + }); + + it('should send an error response if the request is invalid', () => { + const validateCreateConversationRequestSpy = jest + .spyOn(validateCreateConversationRequest, 'validateCreateConversationRequest') + .mockImplementation(() => ({ toAPIException: jest.fn(() => new Error('I am an error!')) } as any)); + const createConversation = createCreateConversationHandler({} as any); + const req: any = { + body: {}, + }; + const res: any = {}; + const next = jest.fn(); + createConversation(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('I am an error!')); + expect(next).toHaveBeenCalled(); + + validateCreateConversationRequestSpy.mockRestore(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/createConversation.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.ts similarity index 78% rename from packages/emulator/core/src/conversations/middleware/createConversation.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.ts index 0db0659f7..08bb7b33b 100644 --- a/packages/emulator/core/src/conversations/middleware/createConversation.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/createConversation.ts @@ -33,20 +33,20 @@ import { ConversationParameters, ChannelAccount, ConversationAccount } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; import { EmulatorMode } from '@bfemulator/sdk-shared'; -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import Conversation from '../../facility/conversation'; -import createConversationResponse from '../../utils/createResponse/conversation'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import uniqueId from '../../utils/uniqueId'; +import { BotEndpoint } from '../../../../state/botEndpoint'; +import { Conversation } from '../../../../state/conversation'; +import { createConversationResponse } from '../../../../utils/createResponse/createConversationResponse'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { uniqueId } from '../../../../utils/uniqueId'; +import { EmulatorRestServer } from '../../../../restServer'; import { validateCreateConversationRequest } from './errorCondition/createConversationValidator'; -export default function createConversation(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +export function createCreateConversationHandler(emulatorServer: EmulatorRestServer) { + return (req: Request, res: Response, next: Next): any => { const botEndpoint: BotEndpoint = (req as any).botEndpoint; const conversationParameters = req.body; const error = validateCreateConversationRequest(conversationParameters, botEndpoint); @@ -57,7 +57,7 @@ export default function createConversation(botEmulator: BotEmulator) { return; } - const newConversation: Conversation = getConversation(conversationParameters, botEmulator, botEndpoint); + const newConversation: Conversation = getConversation(conversationParameters, emulatorServer, botEndpoint); newConversation.normalize(); const activityId = getActivityId(conversationParameters, botEndpoint, newConversation); @@ -71,22 +71,23 @@ export default function createConversation(botEmulator: BotEmulator) { function getConversation( params: { conversationId: string; members: any[]; mode: EmulatorMode }, - emulator: BotEmulator, + emulatorServer: EmulatorRestServer, endpoint: BotEndpoint ): Conversation { + const { state } = emulatorServer; let conversation: Conversation; if (params.conversationId) { - conversation = emulator.facilities.conversations.conversationById(params.conversationId); + conversation = state.conversations.conversationById(params.conversationId); } if (!conversation) { const { members = [] } = params; const [member] = members; - const currentUserId = emulator.facilities.users.currentUserId; + const currentUserId = state.users.currentUserId; const { id = currentUserId || uniqueId(), name = 'User' } = member || {}; - conversation = emulator.facilities.conversations.newConversation( - emulator, + conversation = state.conversations.newConversation( + emulatorServer, endpoint, { id, name }, params.conversationId, diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.spec.ts new file mode 100644 index 000000000..0905da92a --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.spec.ts @@ -0,0 +1,88 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { deleteActivity } from './deleteActivity'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('deleteActivity handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should delete an activity and send a 200', () => { + const req: any = { + conversation: { + deleteActivity: jest.fn(), + }, + params: { + activityId: 'activity1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + deleteActivity(req, res, next); + + expect(req.conversation.deleteActivity).toHaveBeenCalledWith('activity1'); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const req: any = { + conversation: { + deleteActivity: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }, + params: { + activityId: 'activity1', + }, + }; + const res: any = {}; + const next = jest.fn(); + deleteActivity(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/contactAdded.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.ts similarity index 71% rename from packages/emulator/core/src/emulator/middleware/contactAdded.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.ts index 0e3e168db..b0390d0ae 100644 --- a/packages/emulator/core/src/emulator/middleware/contactAdded.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/deleteActivity.ts @@ -32,23 +32,22 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { ConversationAPIPathParameters } from '../types/conversationAPIPathParameters'; -import { ConversationAware } from './fetchConversation'; +export function deleteActivity(req: Request, res: Response, next: Next): any { + const conversationParameters: ConversationAPIPathParameters = req.params; -export default function contactAdded(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - try { - await req.conversation.sendContactAdded(); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + try { + (req as any).conversation.deleteActivity(conversationParameters.activityId); - next(); - }; + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.spec.ts new file mode 100644 index 000000000..7a561115b --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.spec.ts @@ -0,0 +1,86 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { ErrorCodes } from '@bfemulator/sdk-shared'; +import * as HttpStatus from 'http-status-codes'; + +import { createAPIException } from '../../../../../utils/createResponse/createAPIException'; + +import { validateCreateConversationRequest, CreateConversationError } from './createConversationValidator'; + +describe('validateCreateConversationRequest', () => { + it('should validate against a conversation being created with more than one member', () => { + const result = validateCreateConversationRequest( + { members: [{ name: 'user1' }, { name: 'user2' }] } as any, + undefined + ) as CreateConversationError; + + expect(result.errorCode).toBe(ErrorCodes.BadSyntax); + expect(result.message).toBe('The Emulator only supports creating conversation with 1 member.'); + }); + + it('should validate against a conversation being created without a bot', () => { + const result = validateCreateConversationRequest( + { members: [{ name: 'user1' }] } as any, + undefined + ) as CreateConversationError; + + expect(result.errorCode).toBe(ErrorCodes.MissingProperty); + expect(result.message).toBe('The "Bot" parameter is required'); + }); + + it('should validate against a conversation being created without an endpoint', () => { + const result = validateCreateConversationRequest( + { bot: {}, members: [{ name: 'user1' }] } as any, + undefined + ) as CreateConversationError; + + expect(result.errorCode).toBe(ErrorCodes.MissingProperty); + expect(result.message).toBe('The Emulator only supports bot-created conversation with AppID-bearing bot'); + }); + + it('should create a conversation error that can convert itself into an API exception', () => { + const result = validateCreateConversationRequest( + { members: [{ name: 'user1' }, { name: 'user2' }] } as any, + undefined + ) as CreateConversationError; // too many members error + + expect(result.toAPIException()).toEqual( + createAPIException( + HttpStatus.BAD_REQUEST, + ErrorCodes.BadSyntax, + 'The Emulator only supports creating conversation with 1 member.' + ) + ); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/errorCondition/createConversationValidator.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.ts similarity index 62% rename from packages/emulator/core/src/conversations/middleware/errorCondition/createConversationValidator.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.ts index 77b1b2ebb..dd8318b7f 100644 --- a/packages/emulator/core/src/conversations/middleware/errorCondition/createConversationValidator.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/errorCondition/createConversationValidator.ts @@ -34,55 +34,36 @@ import { APIException, ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; import { ConversationParameters } from 'botframework-schema'; -import BotEndpoint from '../../../facility/botEndpoint'; -import createAPIException from '../../../utils/createResponse/apiException'; +import { BotEndpoint } from '../../../../../state/botEndpoint'; +import { createAPIException } from '../../../../../utils/createResponse/createAPIException'; -class CreateConversationError { - public static TOO_MANY_MEMBERS = new CreateConversationError( - ErrorCodes.BadSyntax, - 'The Emulator only supports creating conversation with 1 member.' - ); - - public static BOT_MISSING = new CreateConversationError( - ErrorCodes.MissingProperty, - 'The "Bot" parameter is required' - ); - - public static APP_ID_MISSING = new CreateConversationError( - ErrorCodes.MissingProperty, - 'The Emulator only supports bot-created conversation with AppID-bearing bot' - ); - - constructor(public errorCode: ErrorCodes, public message: string) { - if (Object.isFrozen(CreateConversationError)) { - throw new Error('The CreateConversationError cannot be constructed'); - } - Object.assign(this, { errorCode, message }); - Object.freeze(this); - } +export class CreateConversationError { + constructor(public errorCode: ErrorCodes, public message: string) {} public toAPIException(): APIException { return createAPIException(HttpStatus.BAD_REQUEST, this.errorCode, this.message); } } -Object.freeze(CreateConversationError); - -function validateCreateConversationRequest( +export function validateCreateConversationRequest( params: ConversationParameters, endpoint: BotEndpoint ): CreateConversationError | void { if (params.members && params.members.length > 1) { - return CreateConversationError.TOO_MANY_MEMBERS; + return new CreateConversationError( + ErrorCodes.BadSyntax, + 'The Emulator only supports creating conversation with 1 member.' + ); } if (!params.bot) { - return CreateConversationError.BOT_MISSING; + return new CreateConversationError(ErrorCodes.MissingProperty, 'The "Bot" parameter is required'); } if (!endpoint) { - return CreateConversationError.APP_ID_MISSING; + return new CreateConversationError( + ErrorCodes.MissingProperty, + 'The Emulator only supports bot-created conversation with AppID-bearing bot' + ); } } - -export { CreateConversationError, validateCreateConversationRequest }; diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.spec.ts new file mode 100644 index 000000000..cf5e4f9d7 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.spec.ts @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { getActivityMembers } from './getActivityMembers'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getActivityMembers handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with activity members', () => { + const req: any = { + conversation: { + members: [], + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getActivityMembers(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, req.conversation.members); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const req: any = { + conversation: { + members: [], + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + getActivityMembers(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.ts new file mode 100644 index 000000000..451315e76 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getActivityMembers.ts @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Request, Response } from 'restify'; + +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; + +export function getActivityMembers(req: Request, res: Response, next: Next): any { + try { + res.send(HttpStatus.OK, (req as any).conversation.members); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); +} diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.spec.ts new file mode 100644 index 000000000..373ed2b10 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.spec.ts @@ -0,0 +1,119 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { BotEndpoint } from '../../../../state/botEndpoint'; + +import { createGetBotEndpointHandler } from './getBotEndpoint'; + +describe('getBotEndpoint handler', () => { + it('should get the bot endpoint and attach it to the request if headers are present and the endpoint exists', () => { + const req: any = { + headers: { + 'x-emulator-appid': 'someAppId', + 'x-emulator-apppassword': 'someAppPw', + 'x-emulator-botendpoint': 'someBotUrl', + 'x-emulator-channelservice': 'azureusgovernment', + }, + }; + const mockEndpoint = {}; + const state: any = { + endpoints: { + get: jest.fn(() => mockEndpoint), + }, + }; + const res: any = {}; + const next = jest.fn(); + const getBotEndpoint = createGetBotEndpointHandler(state); + getBotEndpoint(req, res, next); + + expect(req.botEndpoint).toEqual({ + ...mockEndpoint, + msaAppId: 'someAppId', + msaPassword: 'someAppPw', + }); + expect(next).toHaveBeenCalled(); + }); + + it('should get the bot endpoint and attach it to the request if headers are present and the endpoint exists', () => { + const req: any = { + body: { + bot: { + id: 'bot1', + }, + }, + headers: { + 'x-emulator-appid': 'someAppId', + 'x-emulator-apppassword': 'someAppPw', + 'x-emulator-botendpoint': 'someBotUrl', + 'x-emulator-channelservice': 'not gov', + }, + }; + const state: any = { + endpoints: { + get: jest.fn(() => undefined), + set: jest.fn((_id, endpoint) => endpoint), + }, + }; + const res: any = {}; + const next = jest.fn(); + const getBotEndpoint = createGetBotEndpointHandler(state); + getBotEndpoint(req, res, next); + + const params = req.body; + expect(req.botEndpoint).toEqual( + new BotEndpoint(params.bot.id, params.bot.id, 'someBotUrl', 'someAppId', 'someAppPw', false, undefined) + ); + expect(next).toHaveBeenCalled(); + }); + + it('should get the bot endpoint and attach it to the request if no headers are present', () => { + const req: any = { + jwt: { + appid: 'someAppId', + }, + }; + const mockEndpoint = {}; + const state: any = { + endpoints: { + getByAppId: jest.fn(() => mockEndpoint), + }, + }; + const res: any = {}; + const next = jest.fn(); + const getBotEndpoint = createGetBotEndpointHandler(state); + getBotEndpoint(req, res, next); + + expect(req.botEndpoint).toEqual(mockEndpoint); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/getBotEndpoint.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.ts similarity index 85% rename from packages/emulator/core/src/conversations/middleware/getBotEndpoint.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.ts index 2448c43db..14ba9fd48 100644 --- a/packages/emulator/core/src/conversations/middleware/getBotEndpoint.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getBotEndpoint.ts @@ -30,16 +30,17 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import * as Restify from 'restify'; -import { usGovernmentAuthentication } from '../../authEndpoints'; -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; +import { Next, Request, Response } from 'restify'; -export default function getBotEndpoint(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +import { usGovernmentAuthentication } from '../../../../constants/authEndpoints'; +import { BotEndpoint } from '../../../../state/botEndpoint'; +import { ServerState } from '../../../../state/serverState'; + +export function createGetBotEndpointHandler(state: ServerState) { + return (req: Request, res: Response, next: Next): any => { const request = req as any; - const { endpoints } = botEmulator.facilities; + const { endpoints } = state; /** * IF query params exist, the call is creating a * conversation independent from a bot file. @@ -60,7 +61,7 @@ export default function getBotEndpoint(botEmulator: BotEmulator) { let endpoint = endpoints.get(botUrl); if (!endpoint) { const params = req.body as any; - endpoint = endpoints.push( + endpoint = endpoints.set( null, new BotEndpoint(params.bot.id, params.bot.id, botUrl, msaAppId, msaPassword, false, channelService) ); @@ -75,6 +76,6 @@ export default function getBotEndpoint(botEmulator: BotEmulator) { request.botEndpoint = endpoints.getByAppId(request.jwt.appid); } - return next(); + next(); }; } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.spec.ts new file mode 100644 index 000000000..d066b9775 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.spec.ts @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { ErrorCodes } from '@bfemulator/sdk-shared'; +import * as HttpStatus from 'http-status-codes'; + +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; + +import { createGetConversationHandler } from './getConversation'; + +describe('getConversation handler', () => { + it('should get a conversation and attach it to the conversation', () => { + const state: any = { + conversations: { + conversationById: jest.fn(() => 'some conversation'), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = {}; + const next = jest.fn(); + const getConversation = createGetConversationHandler(state); + getConversation(req, res, next); + + expect(req.conversation).toEqual('some conversation'); + expect(next).toHaveBeenCalled(); + }); + + it('should throw an exception if the conversation is not found', () => { + const state: any = { + conversations: { + conversationById: jest.fn(() => undefined), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = {}; + const next = jest.fn(); + const getConversation = createGetConversationHandler(state); + + try { + getConversation(req, res, next); + expect(true).toBe(false); // ensure that catch is hit + } catch (e) { + expect(e).toEqual(createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found')); + } + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/fetchConversation.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.ts similarity index 76% rename from packages/emulator/core/src/conversations/middleware/fetchConversation.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.ts index be8fa085b..a33bc49a3 100644 --- a/packages/emulator/core/src/conversations/middleware/fetchConversation.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversation.ts @@ -33,16 +33,16 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import ConversationAPIPathParameters from '../conversationAPIPathParameters'; +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; +import { ConversationAPIPathParameters } from '../types/conversationAPIPathParameters'; +import { ServerState } from '../../../../state/serverState'; -export default function fetchConversation(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +export function createGetConversationHandler(state: ServerState) { + return (req: Request, res: Response, next: Next): any => { const conversationParameters: ConversationAPIPathParameters = req.params; - const conversation = botEmulator.facilities.conversations.conversationById(conversationParameters.conversationId); + const conversation = state.conversations.conversationById(conversationParameters.conversationId); if (!conversation) { throw createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found'); @@ -50,6 +50,6 @@ export default function fetchConversation(botEmulator: BotEmulator) { (req as any).conversation = conversation; - return next(); + next(); }; } diff --git a/packages/emulator/core/src/conversations/middleware/updateActivity.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.spec.ts similarity index 52% rename from packages/emulator/core/src/conversations/middleware/updateActivity.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.spec.ts index a791f7060..73434374c 100644 --- a/packages/emulator/core/src/conversations/middleware/updateActivity.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.spec.ts @@ -31,41 +31,54 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { ErrorCodes, ResourceResponse } from '@bfemulator/sdk-shared'; -import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import ConversationAPIPathParameters from '../conversationAPIPathParameters'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { getConversationMembers } from './getConversationMembers'; -export default function updateActivity(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - const activity = req.body as Activity; - const conversationParameters: ConversationAPIPathParameters = req.params; +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); - try { - activity.replyToId = conversationParameters.activityId; +describe('getConversationMembers handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); - if (activity.id !== conversationParameters.activityId) { - throw createAPIException( - HttpStatus.BAD_REQUEST, - ErrorCodes.BadArgument, - 'uri activity id does not match payload activity id' - ); - } + it('should send a 200 with the conversation members', () => { + const req: any = { + conversation: { + members: [], + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getConversationMembers(req, res, next); - // post activity - const response: ResourceResponse = (req as any).conversation.updateActivity(activity); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, req.conversation.members); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); - res.send(HttpStatus.OK, response); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + it('should send an error response if something goes wrong', () => { + const req: any = { + conversation: { + members: [], + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + getConversationMembers(req, res, next); - next(); - }; -} + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/getConversationData.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.ts similarity index 75% rename from packages/emulator/core/src/botState/middleware/getConversationData.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.ts index 34816252e..976dae570 100644 --- a/packages/emulator/core/src/botState/middleware/getConversationData.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversationMembers.ts @@ -32,20 +32,19 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; -export default function getConversationData(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - res.send(HttpStatus.OK, (req as any).botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +// get members of a conversation +export function getConversationMembers(req: Request, res: Response, next: Next): any { + try { + // look up conversation + res.send(HttpStatus.OK, (req as any).conversation.members); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } - next(); - }; + next(); } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.spec.ts new file mode 100644 index 000000000..ff539f0b2 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.spec.ts @@ -0,0 +1,137 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createGetConversationsHandler } from './getConversations'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getConversations handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with the conversations matching the conversation id and after the first matching id', () => { + const mockConversations = [ + { conversationId: 'convo0', members: [] }, + { conversationId: 'convo1', members: [] }, + { conversationId: 'convo2', members: [] }, + ]; + const state: any = { + conversations: { + getConversations: jest.fn(() => mockConversations), + }, + }; + const req: any = { + params: { + continuationToken: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const getConversations = createGetConversationsHandler(state); + getConversations(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { + conversations: [ + { id: mockConversations[1].conversationId, members: mockConversations[1].members }, + { id: mockConversations[2].conversationId, members: mockConversations[2].members }, + ], + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 200 with all conversations if no id is specified', () => { + const mockConversations = [ + { conversationId: 'convo0', members: [] }, + { conversationId: 'convo1', members: [] }, + { conversationId: 'convo2', members: [] }, + ]; + const state: any = { + conversations: { + getConversations: jest.fn(() => mockConversations), + }, + }; + const req: any = { + params: {}, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const getConversations = createGetConversationsHandler(state); + getConversations(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { + conversations: mockConversations.map(convo => ({ + id: convo.conversationId, + members: convo.members, + })), + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const mockConversations = []; + const state: any = { + conversations: { + getConversations: jest.fn(() => mockConversations), + }, + }; + const req: any = { + params: {}, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + const getConversations = createGetConversationsHandler(state); + getConversations(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/getConversations.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.ts similarity index 86% rename from packages/emulator/core/src/conversations/middleware/getConversations.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.ts index 66336eaac..fd06e86ce 100644 --- a/packages/emulator/core/src/conversations/middleware/getConversations.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/getConversations.ts @@ -32,22 +32,22 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; import { ConversationMembers, ConversationsGetConversationsOptionalParams, ConversationsGetConversationsResponse, } from 'botframework-connector/lib/connectorApi/models'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import { Conversation } from '../../index'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { Conversation } from '../../../../state/conversation'; +import { ServerState } from '../../../../state/serverState'; -export default function fetchConversations(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): void => { +export function createGetConversationsHandler(state: ServerState) { + return (req: Request, res: Response, next: Next): void => { const conversationParameters: ConversationsGetConversationsOptionalParams = req.params; const { continuationToken } = conversationParameters; - const { conversations: api } = botEmulator.facilities; + const { conversations: api } = state; const conversations = api.getConversations(); const response = {} as ConversationsGetConversationsResponse; diff --git a/packages/emulator/core/src/conversations/middleware/replyToActivity.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.spec.ts similarity index 85% rename from packages/emulator/core/src/conversations/middleware/replyToActivity.spec.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.spec.ts index d40967562..b9066d324 100644 --- a/packages/emulator/core/src/conversations/middleware/replyToActivity.spec.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.spec.ts @@ -33,14 +33,14 @@ import { OK } from 'http-status-codes'; -import replyToActivity from './replyToActivity'; +import { createReplyToActivityHandler } from './replyToActivity'; const mockResolveOAuthCards = jest.fn().mockResolvedValue(true); -jest.mock('../../utils/oauthLinkEncoder', () => { - return jest.fn().mockImplementation(() => { +jest.mock('../../../../utils/oauthLinkEncoder', () => ({ + OAuthLinkEncoder: jest.fn().mockImplementation(() => { return { resolveOAuthCards: mockResolveOAuthCards }; - }); -}); + }), +})); describe('replyToActivity route middleware', () => { const mockReq: any = { @@ -63,11 +63,9 @@ describe('replyToActivity route middleware', () => { send: jest.fn(() => null), }; const mockNext: any = jest.fn(() => null); - const mockBotEmulator: any = { - facilities: { - logger: { - logException: jest.fn(() => null), - }, + const mockEmulatorServer: any = { + logger: { + logException: jest.fn(() => null), }, }; @@ -77,11 +75,11 @@ describe('replyToActivity route middleware', () => { mockRes.end.mockClear(); mockRes.send.mockClear(); mockNext.mockClear(); - mockBotEmulator.facilities.logger.logException.mockClear(); + mockEmulatorServer.logger.logException.mockClear(); }); it('should resolve any OAuth cards, post the activity to the user, and send an OK response', async () => { - replyToActivity(mockBotEmulator)(mockReq, mockRes, mockNext); + createReplyToActivityHandler(mockEmulatorServer)(mockReq, mockRes, mockNext); // since the middleware is not an async function, wait for the async operations to complete await new Promise(resolve => setTimeout(resolve, 500)); @@ -98,7 +96,7 @@ describe('replyToActivity route middleware', () => { it('should resolve any OAuth cards, post the activity (with a null id) to the user, and send an OK response', async () => { mockReq.body.id = undefined; - replyToActivity(mockBotEmulator)(mockReq, mockRes, mockNext); + createReplyToActivityHandler(mockEmulatorServer)(mockReq, mockRes, mockNext); // since the middleware is not an async function, wait for the async operations to complete await new Promise(resolve => setTimeout(resolve, 500)); @@ -118,13 +116,13 @@ describe('replyToActivity route middleware', () => { it('should log any exceptions from OAuth signin in generation before posting the activity to the user', async () => { const ngrokError = new Error('Failed to spawn ngrok'); mockResolveOAuthCards.mockRejectedValueOnce(ngrokError); - replyToActivity(mockBotEmulator)(mockReq, mockRes, mockNext); + createReplyToActivityHandler(mockEmulatorServer)(mockReq, mockRes, mockNext); // since the middleware is not an async function, wait for the async operations to complete await new Promise(resolve => setTimeout(resolve, 500)); - expect(mockBotEmulator.facilities.logger.logException).toHaveBeenCalledWith('someConversationId', ngrokError); - expect(mockBotEmulator.facilities.logger.logException).toHaveBeenCalledWith( + expect(mockEmulatorServer.logger.logException).toHaveBeenCalledWith('someConversationId', ngrokError); + expect(mockEmulatorServer.logger.logException).toHaveBeenCalledWith( 'someConversationId', new Error('Falling back to emulated OAuth token.') ); diff --git a/packages/emulator/core/src/conversations/middleware/replyToActivity.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.ts similarity index 73% rename from packages/emulator/core/src/conversations/middleware/replyToActivity.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.ts index 0a9b4901c..efac8da73 100644 --- a/packages/emulator/core/src/conversations/middleware/replyToActivity.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/replyToActivity.ts @@ -34,17 +34,18 @@ import { ResourceResponse } from '@bfemulator/sdk-shared'; import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import OAuthLinkEncoder from '../../utils/oauthLinkEncoder'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import ConversationAPIPathParameters from '../conversationAPIPathParameters'; +import { OAuthLinkEncoder } from '../../../../utils/oauthLinkEncoder'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { ConversationAPIPathParameters } from '../types/conversationAPIPathParameters'; +import { EmulatorRestServer } from '../../../../restServer'; -export default function replyToActivity(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +export function createReplyToActivityHandler(emulatorServer: EmulatorRestServer) { + return (req: Request, res: Response, next: Next): any => { const activity = req.body as Activity; const conversationParameters: ConversationAPIPathParameters = req.params; + const { logger } = emulatorServer; try { activity.id = activity.id || null; @@ -58,7 +59,12 @@ export default function replyToActivity(botEmulator: BotEmulator) { }; const { conversationId } = conversationParameters; - const visitor = new OAuthLinkEncoder(botEmulator, req.headers.authorization as string, activity, conversationId); + const visitor = new OAuthLinkEncoder( + emulatorServer, + req.headers.authorization as string, + activity, + conversationId + ); visitor .resolveOAuthCards(activity) .then(_ => { @@ -67,11 +73,8 @@ export default function replyToActivity(botEmulator: BotEmulator) { .catch( // failed to generate an OAuth signin link (reason: any) => { - botEmulator.facilities.logger.logException(conversationId, reason); - botEmulator.facilities.logger.logException( - conversationId, - new Error('Falling back to emulated OAuth token.') - ); + logger.logException(conversationId, reason); + logger.logException(conversationId, new Error('Falling back to emulated OAuth token.')); continuation(); } ); diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.spec.ts new file mode 100644 index 000000000..870e8f899 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.spec.ts @@ -0,0 +1,89 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { sendActivityToConversation } from './sendActivityToConversation'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('sendActivityToConversation handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with a response from posting the activity', () => { + const req: any = { + body: {}, + conversation: { + postActivityToUser: jest.fn(() => 'post activity response'), + }, + params: { + activityId: 'activity1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + sendActivityToConversation(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, 'post activity response'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const req: any = { + body: {}, + conversation: { + postActivityToUser: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }, + params: { + activityId: 'activity1', + }, + }; + const res: any = {}; + const next = jest.fn(); + sendActivityToConversation(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/sendActivityToConversation.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.ts similarity index 68% rename from packages/emulator/core/src/conversations/middleware/sendActivityToConversation.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.ts index e26ec6595..4af2d315d 100644 --- a/packages/emulator/core/src/conversations/middleware/sendActivityToConversation.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/sendActivityToConversation.ts @@ -34,27 +34,24 @@ import { ResourceResponse } from '@bfemulator/sdk-shared'; import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; -export default function sendActivityToConversation(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - const activity = req.body as Activity; - try { - activity.id = null; - activity.replyToId = req.params.activityId; +export function sendActivityToConversation(req: Request, res: Response, next: Next): any { + const activity = req.body as Activity; + try { + activity.id = null; + activity.replyToId = req.params.activityId; - // post activity - const response: ResourceResponse = (req as any).conversation.postActivityToUser(activity); + // post activity + const response: ResourceResponse = (req as any).conversation.postActivityToUser(activity); - res.send(HttpStatus.OK, response); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + res.send(HttpStatus.OK, response); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } - next(); - }; + next(); } diff --git a/packages/emulator/core/src/botState/middleware/setConversationData.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.spec.ts similarity index 59% rename from packages/emulator/core/src/botState/middleware/setConversationData.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.spec.ts index 34b4c47e0..79110413f 100644 --- a/packages/emulator/core/src/botState/middleware/setConversationData.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.spec.ts @@ -31,29 +31,36 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { BotData } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createResourceResponse } from '../../../../utils/createResponse/createResourceResponse'; -export default function setConversationData(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const botData = botEmulator.facilities.botState.setBotData( - req.params.channelId, - req.params.conversationId, - req.params.userId, - req.body as BotData - ); +import { sendHistoryToConversation } from './sendHistoryToConversation'; - res.send(HttpStatus.OK, botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +describe('sendHistoryToConversation handler', () => { + it('should send activity history to a conversation', () => { + const req: any = { + body: { + activities: ['activity1', 'activity2', 'activity3'], + }, + conversation: { + postActivityToUser: jest.fn().mockImplementationOnce(() => { + throw new Error('Something went wrong.'); + }), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + sendHistoryToConversation(req, res, next); - next(); - }; -} + expect(res.send).toHaveBeenCalledWith( + HttpStatus.OK, + createResourceResponse(`Processed ${2} of ${3} activities successfully.${new Error('Something went wrong.')}`) + ); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/addUsers.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.ts similarity index 64% rename from packages/emulator/core/src/emulator/middleware/addUsers.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.ts index 3bd0941ad..738ccf442 100644 --- a/packages/emulator/core/src/emulator/middleware/addUsers.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/sendHistoryToConversation.ts @@ -31,30 +31,30 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { ChannelAccount } from 'botframework-schema'; +import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createResourceResponse } from '../../../../utils/createResponse/createResourceResponse'; -import { ConversationAware } from './fetchConversation'; +export function sendHistoryToConversation(req: Request, res: Response, next: Next): any { + const { activities }: { activities: Activity[] } = req.body; + let successCount = 0; + let firstErrorMessage = ''; -export default function addUsers(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { + for (const activity of activities) { try { - const members: ChannelAccount[] = JSON.parse(req.body || '[]'); - const it = members[Symbol.iterator](); // Node does not support array.values() :( - let member; - while ((member = it.next().value)) { - await req.conversation.addMember(member.id, member.name); - } - res.send(HttpStatus.OK); - res.end(); + (req as any).conversation.postActivityToUser(activity, true); + successCount++; } catch (err) { - sendErrorResponse(req, res, next, err); + if (firstErrorMessage === '') { + firstErrorMessage = err; + } } - - next(); - }; + } + const id = `Processed ${successCount} of ${activities.length} activities successfully.${firstErrorMessage}`; + const response = createResourceResponse(id); + res.send(HttpStatus.OK, response); + res.end(); + next(); } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.spec.ts new file mode 100644 index 000000000..3c6ad1055 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.spec.ts @@ -0,0 +1,101 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { ErrorCodes, ResourceResponse } from '@bfemulator/sdk-shared'; +import * as HttpStatus from 'http-status-codes'; + +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; + +import { updateActivity } from './updateActivity'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('updateActivity handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should update an activity and return a resource response with a 200', () => { + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + updateActivity: jest.fn(() => 'update successful'), + }, + params: { + activityId: 'activity1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + updateActivity(req, res, next); + + expect(req.conversation.updateActivity).toHaveBeenCalledWith(req.body); + expect(res.send).toHaveBeenCalled(); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response when the acitivty ids do not match', () => { + const req: any = { + body: { + id: 'activity1', + }, + params: { + activityId: 'activity2', + }, + }; + const res: any = {}; + const next = jest.fn(); + updateActivity(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith( + req, + res, + next, + createAPIException( + HttpStatus.BAD_REQUEST, + ErrorCodes.BadArgument, + 'uri activity id does not match payload activity id' + ) + ); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/sendHistoryToConversation.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.ts similarity index 59% rename from packages/emulator/core/src/conversations/middleware/sendHistoryToConversation.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.ts index dc7530b19..2b37892e4 100644 --- a/packages/emulator/core/src/conversations/middleware/sendHistoryToConversation.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/updateActivity.ts @@ -31,33 +31,38 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +import { ErrorCodes, ResourceResponse } from '@bfemulator/sdk-shared'; import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import createResourceResponse from '../../utils/createResponse/resource'; - -export default function sendHistoryToConversation(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - const { activities }: { activities: Activity[] } = req.body; - let successCount = 0; - let firstErrorMessage = ''; - - for (const activity of activities) { - try { - (req as any).conversation.postActivityToUser(activity, true); - successCount++; - } catch (err) { - if (firstErrorMessage === '') { - firstErrorMessage = err; - } - } +import { Next, Request, Response } from 'restify'; + +import { createAPIException } from '../../../../utils/createResponse/createAPIException'; +import { ConversationAPIPathParameters } from '../types/conversationAPIPathParameters'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; + +export function updateActivity(req: Request, res: Response, next: Next): any { + const activity = req.body as Activity; + const conversationParameters: ConversationAPIPathParameters = req.params; + + try { + activity.replyToId = conversationParameters.activityId; + + if (activity.id !== conversationParameters.activityId) { + throw createAPIException( + HttpStatus.BAD_REQUEST, + ErrorCodes.BadArgument, + 'uri activity id does not match payload activity id' + ); } - const id = `Processed ${successCount} of ${activities.length} activities successfully.${firstErrorMessage}`; - const response = createResourceResponse(id); + + // post activity + const response: ResourceResponse = (req as any).conversation.updateActivity(activity); + res.send(HttpStatus.OK, response); res.end(); - next(); - }; + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); } diff --git a/packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.spec.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.spec.ts new file mode 100644 index 000000000..d29a4bad3 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.spec.ts @@ -0,0 +1,88 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createUploadAttachmentHandler } from './uploadAttachment'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('uploadAttachment handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should upload the attachment and return a resource response with a 200', () => { + const state: any = { + attachments: { + uploadAttachment: jest.fn(() => 'resourceId'), + }, + }; + const req: any = { + body: 'someData', + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const uploadAttachment = createUploadAttachmentHandler(state); + uploadAttachment(req, res, next); + + expect(state.attachments.uploadAttachment).toHaveBeenCalledWith('someData'); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { id: 'resourceId' }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const state: any = { + attachments: { + uploadAttachment: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }, + }; + const req: any = { body: {} }; + const res: any = {}; + const next = jest.fn(); + const uploadAttachment = createUploadAttachmentHandler(state); + uploadAttachment(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/uploadAttachment.ts b/packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.ts similarity index 82% rename from packages/emulator/core/src/conversations/middleware/uploadAttachment.ts rename to packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.ts index 99c0f60cf..055a5daaa 100644 --- a/packages/emulator/core/src/conversations/middleware/uploadAttachment.ts +++ b/packages/app/main/src/server/routes/channel/conversations/handlers/uploadAttachment.ts @@ -33,17 +33,17 @@ import { AttachmentData, ResourceResponse } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { ServerState } from '../../../../state/serverState'; -export default function uploadAttachment(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +export function createUploadAttachmentHandler(state: ServerState) { + return (req: Request, res: Response, next: Next): any => { const attachmentData = req.body as AttachmentData; try { - const resourceId = botEmulator.facilities.attachments.uploadAttachment(attachmentData); + const resourceId = state.attachments.uploadAttachment(attachmentData); const resourceResponse: ResourceResponse = { id: resourceId }; res.send(HttpStatus.OK, resourceResponse); diff --git a/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.spec.ts b/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.spec.ts new file mode 100644 index 000000000..58ce1e99b --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.spec.ts @@ -0,0 +1,179 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createBotFrameworkAuthenticationMiddleware } from '../../handlers/botFrameworkAuthentication'; +import { createJsonBodyParserMiddleware } from '../../../utils/jsonBodyParser'; + +import { mountConversationsRoutes } from './mountConversationsRoutes'; +import { createCreateConversationHandler } from './handlers/createConversation'; +import { deleteActivity } from './handlers/deleteActivity'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { getActivityMembers } from './handlers/getActivityMembers'; +import { createGetBotEndpointHandler } from './handlers/getBotEndpoint'; +import { getConversationMembers } from './handlers/getConversationMembers'; +import { createReplyToActivityHandler } from './handlers/replyToActivity'; +import { sendActivityToConversation } from './handlers/sendActivityToConversation'; +import { sendHistoryToConversation } from './handlers/sendHistoryToConversation'; +import { updateActivity } from './handlers/updateActivity'; +import { createUploadAttachmentHandler } from './handlers/uploadAttachment'; + +jest.mock('../../handlers/botFrameworkAuthentication', () => ({ + createBotFrameworkAuthenticationMiddleware: jest.fn(), +})); +jest.mock('../../../utils/jsonBodyParser', () => ({ createJsonBodyParserMiddleware: jest.fn() })); +jest.mock('./handlers/createConversation', () => ({ + createCreateConversationHandler: jest.fn(), +})); +jest.mock('./handlers/deleteActivity', () => ({ + deleteActivity: jest.fn(), +})); +jest.mock('./handlers/getConversation', () => ({ + createGetConversationHandler: jest.fn(), +})); +jest.mock('./handlers/getActivityMembers', () => ({ + getActivityMembers: jest.fn(), +})); +jest.mock('./handlers/getBotEndpoint', () => ({ + createGetBotEndpointHandler: jest.fn(), +})); +jest.mock('./handlers/getConversationMembers', () => ({ + getConversationMembers: jest.fn(), +})); +jest.mock('./handlers/replyToActivity', () => ({ + createReplyToActivityHandler: jest.fn(), +})); +jest.mock('./handlers/sendActivityToConversation', () => ({ + sendActivityToConversation: jest.fn(), +})); +jest.mock('./handlers/sendHistoryToConversation', () => ({ + sendHistoryToConversation: jest.fn(), +})); +jest.mock('./handlers/updateActivity', () => ({ + updateActivity: jest.fn(), +})); +jest.mock('./handlers/uploadAttachment', () => ({ + createUploadAttachmentHandler: jest.fn(), +})); + +describe('mountConversationsRoutes', () => { + it('should mount the routes', () => { + const get = jest.fn(); + const post = jest.fn(); + const del = jest.fn(); + const put = jest.fn(); + const server: any = { + get, + post, + del, + put, + }; + const emulatorServer: any = { + options: { fetch: jest.fn() }, + server, + state: {}, + }; + const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulatorServer.options.fetch); + const botEndpoint = createGetBotEndpointHandler(emulatorServer.state); + const jsonBodyParser = createJsonBodyParserMiddleware(); + const fetchConversation = createGetConversationHandler(emulatorServer.state); + mountConversationsRoutes(emulatorServer); + + expect(post).toHaveBeenCalledWith( + '/v3/conversations', + verifyBotFramework, + jsonBodyParser, + botEndpoint, + createCreateConversationHandler(emulatorServer) + ); + + expect(post).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + sendActivityToConversation + ); + + expect(post).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities/history', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + sendHistoryToConversation + ); + + expect(post).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + createReplyToActivityHandler(emulatorServer) + ); + + expect(put).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + updateActivity + ); + + expect(del).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + fetchConversation, + deleteActivity + ); + + expect(get).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/members', + verifyBotFramework, + fetchConversation, + getConversationMembers + ); + + expect(get).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/activities/:activityId/members', + verifyBotFramework, + fetchConversation, + getActivityMembers + ); + + expect(post).toHaveBeenCalledWith( + '/v3/conversations/:conversationId/attachments', + verifyBotFramework, + jsonBodyParser, + createUploadAttachmentHandler(emulatorServer.state) + ); + }); +}); diff --git a/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.ts b/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.ts new file mode 100644 index 000000000..cf63e87b8 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/conversations/mountConversationsRoutes.ts @@ -0,0 +1,126 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createBotFrameworkAuthenticationMiddleware } from '../../handlers/botFrameworkAuthentication'; +import { createJsonBodyParserMiddleware } from '../../../utils/jsonBodyParser'; +import { EmulatorRestServer } from '../../../restServer'; + +import { createCreateConversationHandler } from './handlers/createConversation'; +import { deleteActivity } from './handlers/deleteActivity'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { getActivityMembers } from './handlers/getActivityMembers'; +import { getConversationMembers } from './handlers/getConversationMembers'; +import { createReplyToActivityHandler } from './handlers/replyToActivity'; +import { sendActivityToConversation } from './handlers/sendActivityToConversation'; +import { sendHistoryToConversation } from './handlers/sendHistoryToConversation'; +import { updateActivity } from './handlers/updateActivity'; +import { createUploadAttachmentHandler } from './handlers/uploadAttachment'; +import { createGetConversationsHandler } from './handlers/getConversations'; +import { createGetBotEndpointHandler } from './handlers/getBotEndpoint'; + +export function mountConversationsRoutes(emulatorServer: EmulatorRestServer) { + const { server, state } = emulatorServer; + const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulatorServer.options.fetch); + const jsonBodyParser = createJsonBodyParserMiddleware(); + const fetchConversation = createGetConversationHandler(state); + + server.post( + '/v3/conversations', + verifyBotFramework, + jsonBodyParser, + createGetBotEndpointHandler(state), + createCreateConversationHandler(emulatorServer) + ); + + server.post( + '/v3/conversations/:conversationId/activities', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + sendActivityToConversation + ); + + server.post( + '/v3/conversations/:conversationId/activities/history', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + sendHistoryToConversation + ); + + server.post( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + createReplyToActivityHandler(emulatorServer) + ); + + server.put( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + jsonBodyParser, + fetchConversation, + updateActivity + ); + + server.del( + '/v3/conversations/:conversationId/activities/:activityId', + verifyBotFramework, + fetchConversation, + deleteActivity + ); + + server.get('/v3/conversations', verifyBotFramework, createGetConversationsHandler(state)); + + server.get( + '/v3/conversations/:conversationId/members', + verifyBotFramework, + fetchConversation, + getConversationMembers + ); + + server.get( + '/v3/conversations/:conversationId/activities/:activityId/members', + verifyBotFramework, + fetchConversation, + getActivityMembers + ); + + server.post( + '/v3/conversations/:conversationId/attachments', + verifyBotFramework, + jsonBodyParser, + createUploadAttachmentHandler(state) + ); +} diff --git a/packages/emulator/core/src/conversations/conversationAPIPathParameters.ts b/packages/app/main/src/server/routes/channel/conversations/types/conversationAPIPathParameters.ts similarity index 94% rename from packages/emulator/core/src/conversations/conversationAPIPathParameters.ts rename to packages/app/main/src/server/routes/channel/conversations/types/conversationAPIPathParameters.ts index 771b5f9c6..e80d67ca6 100644 --- a/packages/emulator/core/src/conversations/conversationAPIPathParameters.ts +++ b/packages/app/main/src/server/routes/channel/conversations/types/conversationAPIPathParameters.ts @@ -31,9 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -interface ConversationAPIPathParameters { +export interface ConversationAPIPathParameters { conversationId: string; activityId: string; } - -export default ConversationAPIPathParameters; diff --git a/packages/emulator/core/src/middleware/getFacility.spec.ts b/packages/app/main/src/server/routes/channel/session/handlers/getSessionId.spec.ts similarity index 79% rename from packages/emulator/core/src/middleware/getFacility.spec.ts rename to packages/app/main/src/server/routes/channel/session/handlers/getSessionId.spec.ts index bce1e428b..0a1b5e1fa 100644 --- a/packages/emulator/core/src/middleware/getFacility.spec.ts +++ b/packages/app/main/src/server/routes/channel/session/handlers/getSessionId.spec.ts @@ -31,18 +31,20 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import getFacility from './getFacility'; +import * as HttpStatus from 'http-status-codes'; -describe('getFacility', () => { - it('should get the facility', () => { - const facility = 'someFacility'; +import { getSessionId } from './getSessionId'; + +describe('getSessionId handler', () => { + it('should return the session id', () => { const req: any = {}; - const res: any = {}; - const next: any = jest.fn(() => null); - const middleware = getFacility(facility); - middleware(req, res, next); + const res: any = { + json: jest.fn(), + }; + const next = jest.fn(); + getSessionId(req, res, next); - expect(req.facility).toEqual(facility); + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, 'emulatedSession'); expect(next).toHaveBeenCalled(); }); }); diff --git a/packages/emulator/core/src/session/middleware/getSessionId.ts b/packages/app/main/src/server/routes/channel/session/handlers/getSessionId.ts similarity index 83% rename from packages/emulator/core/src/session/middleware/getSessionId.ts rename to packages/app/main/src/server/routes/channel/session/handlers/getSessionId.ts index 90747b3ac..e9921d5bd 100644 --- a/packages/emulator/core/src/session/middleware/getSessionId.ts +++ b/packages/app/main/src/server/routes/channel/session/handlers/getSessionId.ts @@ -32,12 +32,9 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; - -export default function getSessionId(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - res.json(HttpStatus.OK, 'emulatedSession'); - }; +export function getSessionId(req: Request, res: Response, next: Next): any { + res.json(HttpStatus.OK, 'emulatedSession'); + next(); } diff --git a/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.spec.ts b/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.spec.ts new file mode 100644 index 000000000..88f29db48 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.spec.ts @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { tokenRedirect } from './tokenRedirect'; + +const body = + '' + + 'Botframework Emulator' + + '' + + ''; + +describe('tokenRedirect handler', () => { + it('should redirect as part of the AAD token flow', () => { + const req: any = {}; + const res: any = { + end: jest.fn(), + write: jest.fn(), + writeHead: jest.fn(), + }; + const next = jest.fn(); + tokenRedirect(req, res, next); + + expect(res.writeHead).toHaveBeenCalledWith(200, { + 'Content-Length': Buffer.byteLength(body), + 'Content-Type': 'text/html', + }); + expect(res.write).toHaveBeenCalledWith(body); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.ts b/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.ts new file mode 100644 index 000000000..6a6b5e06e --- /dev/null +++ b/packages/app/main/src/server/routes/channel/session/handlers/tokenRedirect.ts @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { Next, Request, Response } from 'restify'; + +const body = + '' + + 'Botframework Emulator' + + '' + + ''; + +export function tokenRedirect(req: Request, res: Response, next: Next) { + res.writeHead(200, { + 'Content-Length': Buffer.byteLength(body), + 'Content-Type': 'text/html', + }); + res.write(body); + res.end(); + next(); +} diff --git a/packages/app/main/src/server/routes/channel/session/mountSessionRoutes.spec.ts b/packages/app/main/src/server/routes/channel/session/mountSessionRoutes.spec.ts new file mode 100644 index 000000000..39a858bc8 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/session/mountSessionRoutes.spec.ts @@ -0,0 +1,54 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { getSessionId } from './handlers/getSessionId'; +import { tokenRedirect } from './handlers/tokenRedirect'; +import { mountSessionRoutes } from './mountSessionRoutes'; + +jest.mock('./handlers/getSessionId', () => jest.fn()); + +describe('mountSessionRoutes', () => { + it('should mount the routes', () => { + const get = jest.fn(); + const server: any = { + get, + }; + const emulatorServer: any = { + server, + }; + mountSessionRoutes(emulatorServer); + + expect(get).toHaveBeenCalledWith('/v3/directline/session/getsessionid', getSessionId); + expect(get).toHaveBeenCalledWith('/v4/token', tokenRedirect); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/getConversation.ts b/packages/app/main/src/server/routes/channel/session/mountSessionRoutes.ts similarity index 78% rename from packages/emulator/core/src/directLine/middleware/getConversation.ts rename to packages/app/main/src/server/routes/channel/session/mountSessionRoutes.ts index fac12e172..8aeb11cbe 100644 --- a/packages/emulator/core/src/directLine/middleware/getConversation.ts +++ b/packages/app/main/src/server/routes/channel/session/mountSessionRoutes.ts @@ -31,14 +31,15 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import * as Restify from 'restify'; +import { EmulatorRestServer } from '../../../restServer'; -import { BotEmulator } from '../../botEmulator'; +import { getSessionId } from './handlers/getSessionId'; +import { tokenRedirect } from './handlers/tokenRedirect'; -export default function getConversation(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - (req as any).conversation = botEmulator.facilities.conversations.conversationById(req.params.conversationId); +export function mountSessionRoutes(emulatorServer: EmulatorRestServer) { + const { server } = emulatorServer; - next(); - }; + server.get('/v3/directline/session/getsessionid', getSessionId); + + server.get('/v4/token', tokenRedirect); } diff --git a/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.spec.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.spec.ts new file mode 100644 index 000000000..ab0352634 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.spec.ts @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { OAuthLinkEncoder } from '../../../../utils/oauthLinkEncoder'; + +import { emulateOAuthCards } from './emulateOAuthCards'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('emulateOAuthCards handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should set the emulation flag accordingly and return a 200', () => { + OAuthLinkEncoder.EmulateOAuthCards = false; + const req: any = { params: { emulate: 'true' } }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + emulateOAuthCards(req, res, next); + + expect(OAuthLinkEncoder.EmulateOAuthCards).toBe(true); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const req: any = { params: {} }; + const res: any = { + end: jest.fn(), + send: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + emulateOAuthCards(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.ts new file mode 100644 index 000000000..29a5e3284 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/emulateOAuthCards.ts @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import * as Restify from 'restify'; + +import { OAuthLinkEncoder } from '../../../../utils/oauthLinkEncoder'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; + +export function emulateOAuthCards(req: Restify.Request, res: Restify.Response, next: Restify.Next): any { + try { + const emulate: string = req.params.emulate; + if (emulate) { + OAuthLinkEncoder.EmulateOAuthCards = emulate.toLowerCase() === 'true'; + } else { + OAuthLinkEncoder.EmulateOAuthCards = false; + } + res.send(HttpStatus.OK); + + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + next(); +} diff --git a/packages/app/main/src/server/routes/channel/userToken/handlers/getToken.spec.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/getToken.spec.ts new file mode 100644 index 000000000..a893039e3 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/getToken.spec.ts @@ -0,0 +1,105 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { TokenCache } from '../tokenCache'; + +import { getToken } from './getToken'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getToken handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should return a 200 and the token if successful', () => { + const mockTokenResponse: any = 'I am a token'; + const getTokenSpy = jest.spyOn(TokenCache, 'getTokenFromCache').mockReturnValue(mockTokenResponse); + const req: any = { botEndpoint: { botId: 'bot1' }, params: { connectionName: 'conn1', userId: 'user1' } }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getToken(req, res, next); + + expect(getTokenSpy).toHaveBeenCalledWith(req.botEndpoint.botId, req.params.userId, req.params.connectionName); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, mockTokenResponse); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + + getTokenSpy.mockRestore(); + }); + + it('should return a 404 if the token is not found', () => { + const mockTokenResponse: any = undefined; + const getTokenSpy = jest.spyOn(TokenCache, 'getTokenFromCache').mockReturnValue(mockTokenResponse); + const req: any = { botEndpoint: { botId: 'bot1' }, params: { connectionName: 'conn1', userId: 'user1' } }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getToken(req, res, next); + + expect(getTokenSpy).toHaveBeenCalledWith(req.botEndpoint.botId, req.params.userId, req.params.connectionName); + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_FOUND); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + + getTokenSpy.mockRestore(); + }); + + it('should send an error response if something goes wrong', () => { + const getTokenSpy = jest.spyOn(TokenCache, 'getTokenFromCache').mockImplementation(() => { + throw new Error('Something went wrong.'); + }); + const req: any = { botEndpoint: { botId: 'bot1' }, params: { connectionName: 'conn1', userId: 'user1' } }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getToken(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + + getTokenSpy.mockRestore(); + }); +}); diff --git a/packages/emulator/core/src/userToken/middleware/getToken.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/getToken.ts similarity index 63% rename from packages/emulator/core/src/userToken/middleware/getToken.ts rename to packages/app/main/src/server/routes/channel/userToken/handlers/getToken.ts index 659e502df..ecf686c7d 100644 --- a/packages/emulator/core/src/userToken/middleware/getToken.ts +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/getToken.ts @@ -34,37 +34,35 @@ import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { BotEndpoint } from '../../../../state/botEndpoint'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; import { TokenCache } from '../tokenCache'; -import { TokenParams } from '../TokenParams'; -import { TokenResponse } from '../TokenResponse'; +import { TokenParams } from '../types/TokenParams'; +import { TokenResponse } from '../types/TokenResponse'; interface GetTokenParams extends TokenParams { code: string; } -export default function getToken(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const params: GetTokenParams = req.params; - const botEndpoint: BotEndpoint = (req as any).botEndpoint; +export function getToken(req: Restify.Request, res: Restify.Response, next: Restify.Next): any { + try { + const params: GetTokenParams = req.params; + const botEndpoint: BotEndpoint = (req as any).botEndpoint; - const tokenResponse: TokenResponse = TokenCache.getTokenFromCache( - botEndpoint.botId, - params.userId, - params.connectionName - ); - if (tokenResponse) { - res.send(HttpStatus.OK, tokenResponse); - } else { - res.send(HttpStatus.NOT_FOUND); - } - - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); + const tokenResponse: TokenResponse = TokenCache.getTokenFromCache( + botEndpoint.botId, + params.userId, + params.connectionName + ); + if (tokenResponse) { + res.send(HttpStatus.OK, tokenResponse); + } else { + res.send(HttpStatus.NOT_FOUND); } - }; + + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + next(); } diff --git a/packages/app/main/src/server/routes/channel/userToken/handlers/signOut.spec.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/signOut.spec.ts new file mode 100644 index 000000000..6d4dd98f1 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/signOut.spec.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { TokenCache } from '../tokenCache'; + +import { signOut } from './signOut'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('signOut handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should delete the token from cache and send a 200', () => { + const deleteTokenSpy = jest.spyOn(TokenCache, 'deleteTokenFromCache'); + const req: any = { botEndpoint: { botId: 'bot1' }, params: { connectionName: 'conn1', userId: 'user1' } }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + signOut(req, res, next); + + expect(deleteTokenSpy).toHaveBeenCalledWith(req.botEndpoint.botId, req.params.userId, req.params.connectionName); + expect(res.send).toHaveBeenCalled(); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + + deleteTokenSpy.mockRestore(); + }); + + it('should send an error if something goes wrong', () => { + const req: any = { botEndpoint: {}, params: {} }; + const res: any = { + end: jest.fn(), + send: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + signOut(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/sendTokenResponse.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/signOut.ts similarity index 70% rename from packages/emulator/core/src/emulator/middleware/sendTokenResponse.ts rename to packages/app/main/src/server/routes/channel/userToken/handlers/signOut.ts index 36ed932f9..9faa5e9cc 100644 --- a/packages/emulator/core/src/emulator/middleware/sendTokenResponse.ts +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/signOut.ts @@ -34,26 +34,21 @@ import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; +import { BotEndpoint } from '../../../../state/botEndpoint'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; +import { TokenCache } from '../tokenCache'; +import { TokenParams } from '../types/TokenParams'; -import { ConversationAware } from './fetchConversation'; +export function signOut(req: Restify.Request, res: Restify.Response, next: Restify.Next): any { + try { + const params: TokenParams = req.params; + const botEndpoint: BotEndpoint = (req as any).botEndpoint; + TokenCache.deleteTokenFromCache(botEndpoint.botId, params.userId, params.connectionName); -export default function sendTokenResponse(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - const body: { - token: string; - connectionName: string; - } = req.body[0]; - - const { statusCode } = await req.conversation.sendTokenResponse(body.connectionName, body.token, !!1); - - if (statusCode === HttpStatus.OK) { - res.send(HttpStatus.OK, body); - } else { - res.send(statusCode); - } + res.send(HttpStatus.OK); res.end(); - - next(); - }; + } catch (err) { + sendErrorResponse(req, res, next, err); + } + next(); } diff --git a/packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.spec.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.spec.ts new file mode 100644 index 000000000..b8e5ee639 --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.spec.ts @@ -0,0 +1,135 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createTokenResponseHandler } from './tokenResponse'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('tokenResponseHandler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should return a 200 and the request body if successful', async () => { + const req: any = { + body: { connectionName: 'conn1', token: 'myToken' }, + query: { conversationId: 'convo1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const mockSendTokenResponse = jest.fn().mockResolvedValue({ statusCode: HttpStatus.OK }); + const emulatorServer: any = { + shutDownOAuthNgrokInstance: jest.fn(), + state: { + conversations: { + conversationById: jest.fn(() => ({ + sendTokenResponse: mockSendTokenResponse, + })), + }, + }, + }; + const tokenResponse = createTokenResponseHandler(emulatorServer); + await tokenResponse(req, res, next); + + expect(mockSendTokenResponse).toHaveBeenCalledWith(req.body.connectionName, req.body.token, false); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, req.body); + expect(emulatorServer.shutDownOAuthNgrokInstance).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should return the status code of sending the token response if it is not 200', async () => { + const req: any = { + body: { connectionName: 'conn1', token: 'myToken' }, + query: { conversationId: 'convo1' }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const mockSendTokenResponse = jest.fn().mockResolvedValue({ statusCode: HttpStatus.BAD_REQUEST }); + const emulatorServer: any = { + shutDownOAuthNgrokInstance: jest.fn(), + state: { + conversations: { + conversationById: jest.fn(() => ({ + sendTokenResponse: mockSendTokenResponse, + })), + }, + }, + }; + const tokenResponse = createTokenResponseHandler(emulatorServer); + await tokenResponse(req, res, next); + + expect(mockSendTokenResponse).toHaveBeenCalledWith(req.body.connectionName, req.body.token, false); + expect(res.send).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST); + expect(emulatorServer.shutDownOAuthNgrokInstance).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + body: {}, + query: {}, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const emulatorServer: any = { + shutDownOAuthNgrokInstance: jest.fn(), + state: { + conversations: { + conversationById: jest.fn(() => ({ + sendTokenResponse: jest.fn().mockRejectedValue(new Error('Could not send token response.')), + })), + }, + }, + }; + const tokenResponse = createTokenResponseHandler(emulatorServer); + await tokenResponse(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Could not send token response.')); + expect(next).toHaveBeenCalled(); + expect(emulatorServer.shutDownOAuthNgrokInstance).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/userToken/middleware/tokenResponse.ts b/packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.ts similarity index 73% rename from packages/emulator/core/src/userToken/middleware/tokenResponse.ts rename to packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.ts index df7f2c7a1..96bb035ff 100644 --- a/packages/emulator/core/src/userToken/middleware/tokenResponse.ts +++ b/packages/app/main/src/server/routes/channel/userToken/handlers/tokenResponse.ts @@ -34,10 +34,11 @@ import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; +import { EmulatorRestServer } from '../../../../restServer'; +import { sendErrorResponse } from '../../../../utils/sendErrorResponse'; -export default function tokenResponse(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { +export function createTokenResponseHandler(emulatorServer: EmulatorRestServer) { + return async (req: Restify.Request, res: Restify.Response, next: Restify.Next): Promise => { const body: { token: string; connectionName: string; @@ -45,17 +46,22 @@ export default function tokenResponse(botEmulator: BotEmulator) { const conversationId = req.query.conversationId; - const conversation = botEmulator.facilities.conversations.conversationById(conversationId); + const conversation = emulatorServer.state.conversations.conversationById(conversationId); - conversation.sendTokenResponse(body.connectionName, body.token, false).then(response => { - // shut down the oauth ngrok instance - botEmulator.shutDownOAuthNgrokInstance(); + try { + const response = await conversation.sendTokenResponse(body.connectionName, body.token, false); if (response.statusCode === HttpStatus.OK) { res.send(HttpStatus.OK, body); } else { res.send(response.statusCode); } res.end(); - }); + } catch (e) { + sendErrorResponse(req, res, next, e); + } finally { + // shut down the oauth ngrok instance + emulatorServer.shutDownOAuthNgrokInstance(); + } + next(); }; } diff --git a/packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.spec.ts b/packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.spec.ts new file mode 100644 index 000000000..b67f4603b --- /dev/null +++ b/packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.spec.ts @@ -0,0 +1,99 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createGetBotEndpointMiddleware } from '../../handlers/getBotEndpoint'; +import { createBotFrameworkAuthenticationMiddleware } from '../../handlers/botFrameworkAuthentication'; +import { createJsonBodyParserMiddleware } from '../../../utils/jsonBodyParser'; + +import { mountUserTokenRoutes } from './mountUserTokenRoutes'; +import { emulateOAuthCards } from './handlers/emulateOAuthCards'; +import { getToken } from './handlers/getToken'; +import { signOut } from './handlers/signOut'; +import { createTokenResponseHandler } from './handlers/tokenResponse'; + +jest.mock('../../handlers/getBotEndpoint', () => ({ + createGetBotEndpointMiddleware: jest.fn(), +})); +jest.mock('../../handlers/botFrameworkAuthentication', () => ({ + createBotFrameworkAuthenticationMiddleware: jest.fn(), +})); +jest.mock('../../../utils/jsonBodyParser', () => ({ + createJsonBodyParserMiddleware: jest.fn(), +})); +jest.mock('./handlers/tokenResponse', () => ({ + createTokenResponseHandler: jest.fn(), +})); + +describe('mountUserTokenRoutes', () => { + it('should mount the routes', () => { + const emulatorServer: any = { + options: { fetch: jest.fn() }, + server: { + del: jest.fn(), + get: jest.fn(), + post: jest.fn(), + }, + state: {}, + }; + const jsonBodyParser = createJsonBodyParserMiddleware(); + const botFrameworkAuthentication = createBotFrameworkAuthenticationMiddleware(emulatorServer.server.state); + const getBotEndpoint = createGetBotEndpointMiddleware(emulatorServer.server.state); + mountUserTokenRoutes(emulatorServer); + + expect(emulatorServer.server.get).toHaveBeenCalledWith( + '/api/usertoken/GetToken', + botFrameworkAuthentication, + getBotEndpoint, + getToken + ); + + expect(emulatorServer.server.post).toHaveBeenCalledWith( + '/api/usertoken/emulateOAuthCards', + botFrameworkAuthentication, + emulateOAuthCards + ); + + expect(emulatorServer.server.del).toHaveBeenCalledWith( + '/api/usertoken/SignOut', + botFrameworkAuthentication, + getBotEndpoint, + signOut + ); + + expect(emulatorServer.server.post).toHaveBeenCalledWith( + '/api/usertoken/tokenResponse', + jsonBodyParser, + createTokenResponseHandler(emulatorServer) + ); + }); +}); diff --git a/packages/emulator/cli/src/npmLogger.ts b/packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.ts similarity index 51% rename from packages/emulator/cli/src/npmLogger.ts rename to packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.ts index 2f4e42776..6eb269a54 100644 --- a/packages/emulator/cli/src/npmLogger.ts +++ b/packages/app/main/src/server/routes/channel/userToken/mountUserTokenRoutes.ts @@ -31,44 +31,27 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { Logger, LogItem, LogItemType, LogLevel, TextLogItem } from '@bfemulator/sdk-shared'; -import { Activity } from 'botframework-schema'; -import * as log from 'npmlog'; +import { createGetBotEndpointMiddleware } from '../../handlers/getBotEndpoint'; +import { createBotFrameworkAuthenticationMiddleware } from '../../handlers/botFrameworkAuthentication'; +import { createJsonBodyParserMiddleware } from '../../../utils/jsonBodyParser'; +import { EmulatorRestServer } from '../../../restServer'; -function shortId(id: string) { - return [id.substr(0, 3), id.substr(-5)].join('...'); -} - -function logLevel(level: LogLevel) { - switch (level) { - case LogLevel.Error: - return log.error; +import { emulateOAuthCards } from './handlers/emulateOAuthCards'; +import { getToken } from './handlers/getToken'; +import { signOut } from './handlers/signOut'; +import { createTokenResponseHandler } from './handlers/tokenResponse'; - case LogLevel.Info: - return log.info; +export function mountUserTokenRoutes(emulatorServer: EmulatorRestServer) { + const { server, state } = emulatorServer; + const jsonBodyParser = createJsonBodyParserMiddleware(); + const botFrameworkAuthentication = createBotFrameworkAuthenticationMiddleware(emulatorServer.options.fetch); + const getBotEndpoint = createGetBotEndpointMiddleware(state); - case LogLevel.Warn: - return log.warn; - - default: - return log.silly; - } -} + server.get('/api/usertoken/GetToken', botFrameworkAuthentication, getBotEndpoint, getToken); -export default class NpmLogger implements Logger { - public logActivity(conversationId: string, activity: Activity, role: string) { - log.verbose(shortId(conversationId), `Activity to ${role}`, activity); - } + server.post('/api/usertoken/emulateOAuthCards', botFrameworkAuthentication, emulateOAuthCards); - public logMessage(conversationId: string, ...items: LogItem[]) { - items.forEach(message => { - if (message.type === LogItemType.Text) { - logLevel(message.payload.level)(shortId(conversationId), message.payload.text); - } - }); - } + server.del('/api/usertoken/SignOut', botFrameworkAuthentication, getBotEndpoint, signOut); - public logException(conversationId: string, err: Error) { - log.error(shortId(conversationId), err.message); - } + server.post('/api/usertoken/tokenResponse', jsonBodyParser, createTokenResponseHandler(emulatorServer)); } diff --git a/packages/emulator/core/src/userToken/tokenCache.spec.ts b/packages/app/main/src/server/routes/channel/userToken/tokenCache.spec.ts similarity index 100% rename from packages/emulator/core/src/userToken/tokenCache.spec.ts rename to packages/app/main/src/server/routes/channel/userToken/tokenCache.spec.ts diff --git a/packages/emulator/core/src/userToken/tokenCache.ts b/packages/app/main/src/server/routes/channel/userToken/tokenCache.ts similarity index 97% rename from packages/emulator/core/src/userToken/tokenCache.ts rename to packages/app/main/src/server/routes/channel/userToken/tokenCache.ts index f1aa0e897..81e9a784f 100644 --- a/packages/emulator/core/src/userToken/tokenCache.ts +++ b/packages/app/main/src/server/routes/channel/userToken/tokenCache.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { TokenResponse } from './TokenResponse'; +import { TokenResponse } from './types/TokenResponse'; export class TokenCache { private static tokenStore: { [key: string]: TokenResponse } = {}; diff --git a/packages/emulator/core/src/userToken/TokenParams.ts b/packages/app/main/src/server/routes/channel/userToken/types/TokenParams.ts similarity index 100% rename from packages/emulator/core/src/userToken/TokenParams.ts rename to packages/app/main/src/server/routes/channel/userToken/types/TokenParams.ts diff --git a/packages/emulator/core/src/userToken/TokenResponse.ts b/packages/app/main/src/server/routes/channel/userToken/types/TokenResponse.ts similarity index 100% rename from packages/emulator/core/src/userToken/TokenResponse.ts rename to packages/app/main/src/server/routes/channel/userToken/types/TokenResponse.ts diff --git a/packages/app/main/src/server/routes/directLine/handlers/getAcivities.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/getAcivities.spec.ts new file mode 100644 index 000000000..3ee0d8119 --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/getAcivities.spec.ts @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { getActivities } from './getActivities'; + +describe('getActivities handler', () => { + it('should send a 200 with the activities since the speicified watermark', () => { + const activitiesInfo = { + activities: [], + watermark: 20, + }; + const req: any = { + conversation: { + getActivitiesSince: jest.fn(() => activitiesInfo), + }, + query: { + watermark: 20, + }, + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + getActivities(req, res, next); + + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, activitiesInfo); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 404 if there is no conversation attached to the request', () => { + const req: any = { + conversation: undefined, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + getActivities(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, 'conversation not found'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/deleteStateForUser.ts b/packages/app/main/src/server/routes/directLine/handlers/getActivities.ts similarity index 72% rename from packages/emulator/core/src/botState/middleware/deleteStateForUser.ts rename to packages/app/main/src/server/routes/directLine/handlers/getActivities.ts index 1731b154d..597772ba3 100644 --- a/packages/emulator/core/src/botState/middleware/deleteStateForUser.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/getActivities.ts @@ -32,23 +32,25 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { Conversation } from '../../../state/conversation'; -// delete state for user -export default function deleteStateForUser(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - botEmulator.facilities.botState.deleteBotData(req.params.userId); +export function getActivities(req: Request, res: Response, next: Next): any { + const conversation: Conversation = (req as any).conversation; - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + if (conversation) { + const { activities, watermark } = conversation.getActivitiesSince(Number(req.query.watermark || 0) || 0); - next(); - }; + res.json(HttpStatus.OK, { + activities, + watermark, + }); + } else { + res.send(HttpStatus.NOT_FOUND, 'conversation not found'); + } + + res.end(); + + next(); } diff --git a/packages/app/main/src/server/routes/directLine/handlers/getConversation.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/getConversation.spec.ts new file mode 100644 index 000000000..4de975317 --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/getConversation.spec.ts @@ -0,0 +1,57 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createGetConversationHandler } from './getConversation'; + +describe('stream handler', () => { + it('should attach the conversation to the reqiest', () => { + const mockConversation = {}; + const state: any = { + conversations: { + conversationById: jest.fn(() => mockConversation), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = {}; + const next = jest.fn(); + const getConversation = createGetConversationHandler(state); + getConversation(req, res, next); + + expect(req.conversation).toEqual(mockConversation); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/middleware/getRouteName.ts b/packages/app/main/src/server/routes/directLine/handlers/getConversation.ts similarity index 80% rename from packages/emulator/core/src/middleware/getRouteName.ts rename to packages/app/main/src/server/routes/directLine/handlers/getConversation.ts index 24f122b96..e011cf4e1 100644 --- a/packages/emulator/core/src/middleware/getRouteName.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/getConversation.ts @@ -31,11 +31,14 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; + +import { ServerState } from '../../../state/serverState'; + +export function createGetConversationHandler(state: ServerState) { + return (req: Request, res: Response, next: Next): any => { + (req as any).conversation = state.conversations.conversationById(req.params.conversationId); -export default function getRouteName(routeName: string) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - (req as any).routeName = routeName; next(); }; } diff --git a/packages/emulator/core/src/middleware/getRouteName.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/options.spec.ts similarity index 79% rename from packages/emulator/core/src/middleware/getRouteName.spec.ts rename to packages/app/main/src/server/routes/directLine/handlers/options.spec.ts index d2deec26f..ba826e3f9 100644 --- a/packages/emulator/core/src/middleware/getRouteName.spec.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/options.spec.ts @@ -31,18 +31,22 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import getRouteName from './getRouteName'; +import * as HttpStatus from 'http-status-codes'; -describe('getRouteName', () => { - it('should get the route name', () => { - const routeName = 'someRouteName'; +import { options } from './options'; + +describe('options handler', () => { + it('should send a 200', () => { const req: any = {}; - const res: any = {}; - const next: any = jest.fn(() => null); - const middleware = getRouteName(routeName); - middleware(req, res, next); + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + options(req, res, next); - expect(req.routeName).toEqual(routeName); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); expect(next).toHaveBeenCalled(); }); }); diff --git a/packages/emulator/core/src/directLine/middleware/options.ts b/packages/app/main/src/server/routes/directLine/handlers/options.ts similarity index 83% rename from packages/emulator/core/src/directLine/middleware/options.ts rename to packages/app/main/src/server/routes/directLine/handlers/options.ts index 4df25b0f6..1cb8bd3ca 100644 --- a/packages/emulator/core/src/directLine/middleware/options.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/options.ts @@ -32,15 +32,11 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; +export function options(req: Request, res: Response, next: Next): any { + res.send(HttpStatus.OK); + res.end(); -export default function options(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - res.send(HttpStatus.OK); - res.end(); - - next(); - }; + next(); } diff --git a/packages/app/main/src/server/routes/directLine/handlers/postActivity.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/postActivity.spec.ts new file mode 100644 index 000000000..f79df6d2a --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/postActivity.spec.ts @@ -0,0 +1,253 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createPostActivityHandler } from './postActivity'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('postActivity handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should return a 200 and the id of the posted activity', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + postActivityToBot: jest.fn().mockResolvedValueOnce({ + activityId: 'activity1', + response: {}, + statusCode: HttpStatus.OK, + }), + }, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, { id: 'activity1' }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should return a 401 if the request is unauthorized', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + postActivityToBot: jest.fn().mockResolvedValueOnce({ + activityId: 'activity1', + response: { + text: jest.fn().mockResolvedValueOnce('Unauthorized'), + }, + statusCode: HttpStatus.UNAUTHORIZED, + }), + }, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(mockEmulatorServer.logger.logMessage).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.UNAUTHORIZED, 'Unauthorized'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should return a 403 if the request is forbidden', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + postActivityToBot: jest.fn().mockResolvedValueOnce({ + activityId: 'activity1', + response: { + text: jest.fn().mockResolvedValueOnce('Forbidden'), + }, + statusCode: HttpStatus.FORBIDDEN, + }), + }, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(mockEmulatorServer.logger.logMessage).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.FORBIDDEN, 'Forbidden'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should return the status code of a failed request other than a 401 or 403', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + postActivityToBot: jest.fn().mockResolvedValueOnce({ + activityId: 'activity1', + response: { + text: jest.fn().mockResolvedValueOnce('Bad request'), + }, + statusCode: HttpStatus.BAD_REQUEST, + }), + }, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST, 'Bad request'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should return a 500 if the request failed for some reason and there is no status code', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + body: { + id: 'activity1', + }, + conversation: { + postActivityToBot: jest.fn().mockResolvedValueOnce({ + activityId: 'activity1', + response: { + text: jest.fn().mockResolvedValueOnce('Request failed'), + }, + statusCode: undefined, + }), + }, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.INTERNAL_SERVER_ERROR, 'Request failed'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 404 if the conversation is not attached to the request', async () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + conversation: undefined, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const postActivity = createPostActivityHandler(mockEmulatorServer); + await postActivity(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, 'conversation not found'); + expect(res.end).toHaveBeenCalled(); + expect(mockEmulatorServer.logger.logMessage).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/postActivity.ts b/packages/app/main/src/server/routes/directLine/handlers/postActivity.ts similarity index 81% rename from packages/emulator/core/src/directLine/middleware/postActivity.ts rename to packages/app/main/src/server/routes/directLine/handlers/postActivity.ts index 835c03356..2e2e600de 100644 --- a/packages/emulator/core/src/directLine/middleware/postActivity.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/postActivity.ts @@ -34,18 +34,17 @@ import { LogLevel, textItem } from '@bfemulator/sdk-shared'; import { Activity } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import Conversation from '../../facility/conversation'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import statusCodeFamily from '../../utils/statusCodeFamily'; +import { Conversation } from '../../../state/conversation'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; +import { statusCodeFamily } from '../../../utils/statusCodeFamily'; +import { EmulatorRestServer } from '../../../restServer'; -export default function postActivity(botEmulator: BotEmulator) { - const { logMessage } = botEmulator.facilities.logger; +export function createPostActivityHandler(emulatorServer: EmulatorRestServer) { + const { logMessage } = emulatorServer.logger; - return async (req: Restify.Request, res: Restify.Response, next: Restify.Next) => { - // const conversation = botEmulator.facilities.conversations.conversationById(req.params.conversationId); + return async (req: Request, res: Response, next: Next) => { const conversation: Conversation = (req as any).conversation; if (!conversation) { @@ -53,6 +52,7 @@ export default function postActivity(botEmulator: BotEmulator) { res.end(); logMessage(req.params.conversationId, textItem(LogLevel.Error, 'Cannot post activity. Conversation not found.')); + next(); return; } diff --git a/packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.spec.ts new file mode 100644 index 000000000..0b8bbd21e --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.spec.ts @@ -0,0 +1,91 @@ +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createReconnectToConversationHandler } from './reconnectToConversation'; + +describe('reconnectToConversation handler', () => { + it('should send a 200 with the conversation info', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + conversation: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + const reconnectToConversation = createReconnectToConversationHandler(mockEmulatorServer); + reconnectToConversation(req, res, next); + + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, { + conversationId: req.conversation.conversationId, + token: req.conversation.conversationId, + // eslint-disable-next-line typescript/camelcase + expires_in: jasmine.any(Number), + streamUrl: '', + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 404 and log a message if the conversation is not found', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + }; + const req: any = { + conversation: undefined, + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const reconnectToConversation = createReconnectToConversationHandler(mockEmulatorServer); + reconnectToConversation(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, 'conversation not found'); + expect(mockEmulatorServer.logger.logMessage).toHaveBeenCalled(); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/reconnectToConversation.ts b/packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.ts similarity index 85% rename from packages/emulator/core/src/directLine/middleware/reconnectToConversation.ts rename to packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.ts index b3614d61e..55583e77a 100644 --- a/packages/emulator/core/src/directLine/middleware/reconnectToConversation.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/reconnectToConversation.ts @@ -33,15 +33,15 @@ import { LogLevel, textItem } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import Conversation from '../../facility/conversation'; +import { Conversation } from '../../../state/conversation'; +import { EmulatorRestServer } from '../../../restServer'; -export default function reconnectToConversation(botEmulator: BotEmulator) { - const { logMessage } = botEmulator.facilities.logger; +export function createReconnectToConversationHandler(emulatorServer: EmulatorRestServer) { + const { logMessage } = emulatorServer.logger; - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { + return (req: Request, res: Response, next: Next): any => { const conversation: Conversation = (req as any).conversation; if (conversation) { diff --git a/packages/app/main/src/server/routes/directLine/handlers/startConversation.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/startConversation.spec.ts new file mode 100644 index 000000000..77fbaca09 --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/startConversation.spec.ts @@ -0,0 +1,217 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createStartConversationHandler } from './startConversation'; + +describe('startConversation handler', () => { + it('should send a 201 with info about the created conversation if the conversation does not exist', async () => { + const mockCreatedConversation = { + conversationId: 'convo1', + sendConversationUpdate: jest.fn().mockResolvedValueOnce(undefined), + }; + const mockCurrentUser = {}; + const emulatorServer: any = { + state: { + conversations: { + conversationById: jest.fn(() => undefined), + newConversation: jest.fn(() => mockCreatedConversation), + }, + users: { + usersById: jest.fn(() => mockCurrentUser), + }, + }, + }; + const req: any = { + botEndpoint: { + id: 'endpoint1', + }, + header: jest.fn(() => ''), + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + const startConversation = createStartConversationHandler(emulatorServer); + await startConversation(req, res, next); + + expect(mockCreatedConversation.sendConversationUpdate).toHaveBeenCalledWith( + [mockCurrentUser, { id: req.botEndpoint.botId, name: 'Bot' }], + undefined + ); + expect(res.json).toHaveBeenCalledWith(HttpStatus.CREATED, { + conversationId: mockCreatedConversation.conversationId, + token: req.botEndpoint.id, + // eslint-disable-next-line typescript/camelcase + expires_in: jasmine.any(Number), + streamUrl: '', + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 400 if there is no current user while trying to create a conversation', async () => { + const mockCreatedConversation = { + conversationId: 'convo1', + sendConversationUpdate: jest.fn().mockResolvedValueOnce(undefined), + }; + const mockCurrentUser = undefined; + const emulatorServer: any = { + state: { + conversations: { + conversationById: jest.fn(() => undefined), + newConversation: jest.fn(() => mockCreatedConversation), + }, + users: { + usersById: jest.fn(() => mockCurrentUser), + }, + }, + }; + const req: any = { + botEndpoint: { + id: 'endpoint1', + }, + header: jest.fn(() => ''), + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const startConversation = createStartConversationHandler(emulatorServer); + await startConversation(req, res, next); + + expect(mockCreatedConversation.sendConversationUpdate).not.toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST, 'current user not provided'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 200 with info about the conversation if it already exists, and should add members to the conversation', async () => { + const mockCreatedConversation = { + addMember: jest.fn(), + conversationId: 'convo1', + members: { + findIndex: jest.fn(() => -1), // simulate not finding the bot or user in the current conversation + }, + sendConversationUpdate: jest.fn().mockResolvedValueOnce(undefined), + }; + const mockCurrentUser = { id: 'user1', name: 'User' }; + const emulatorServer: any = { + state: { + conversations: { + conversationById: jest.fn(() => mockCreatedConversation), + }, + users: { + usersById: jest.fn(() => mockCurrentUser), + }, + }, + }; + const req: any = { + botEndpoint: { + id: 'endpoint1', + }, + header: jest.fn(() => ''), + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + const startConversation = createStartConversationHandler(emulatorServer); + await startConversation(req, res, next); + + expect(mockCreatedConversation.addMember).toHaveBeenCalledTimes(2); // once for user, and once for bot + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, { + conversationId: mockCreatedConversation.conversationId, + token: req.botEndpoint.id, + // eslint-disable-next-line typescript/camelcase + expires_in: jasmine.any(Number), + streamUrl: '', + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 200 with info about the conversation if it already exists, and should send the conversation updates', async () => { + const mockCreatedConversation = { + addMember: jest.fn(), + conversationId: 'convo1', + members: { + findIndex: jest.fn(() => 0), // simulate finding the bot and user in the current conversation + }, + sendConversationUpdate: jest.fn().mockResolvedValueOnce(undefined), + }; + const mockCurrentUser = { id: 'user1', name: 'User' }; + const emulatorServer: any = { + state: { + conversations: { + conversationById: jest.fn(() => mockCreatedConversation), + }, + users: { + usersById: jest.fn(() => mockCurrentUser), + }, + }, + }; + const req: any = { + botEndpoint: { + id: 'endpoint1', + }, + header: jest.fn(() => ''), + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + const startConversation = createStartConversationHandler(emulatorServer); + await startConversation(req, res, next); + + expect(mockCreatedConversation.addMember).not.toHaveBeenCalled(); + expect(mockCreatedConversation.sendConversationUpdate).toHaveBeenCalledWith( + [mockCurrentUser, { id: req.botEndpoint.botId, name: 'Bot' }], + undefined + ); + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, { + conversationId: mockCreatedConversation.conversationId, + token: req.botEndpoint.id, + // eslint-disable-next-line typescript/camelcase + expires_in: jasmine.any(Number), + streamUrl: '', + }); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/startConversation.ts b/packages/app/main/src/server/routes/directLine/handlers/startConversation.ts similarity index 88% rename from packages/emulator/core/src/directLine/middleware/startConversation.ts rename to packages/app/main/src/server/routes/directLine/handlers/startConversation.ts index b238cea3d..1ed895cde 100644 --- a/packages/emulator/core/src/directLine/middleware/startConversation.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/startConversation.ts @@ -33,14 +33,14 @@ import * as HttpStatus from 'http-status-codes'; import onErrorResumeNext from 'on-error-resume-next'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import uniqueId from '../../utils/uniqueId'; +import { BotEndpoint } from '../../../state/botEndpoint'; +import { uniqueId } from '../../../utils/uniqueId'; +import { EmulatorRestServer } from '../../../restServer'; -export default function startConversation(botEmulator: BotEmulator) { - return async (req: Restify.Request, res: Restify.Response, next: Restify.Next): Promise => { +export function createStartConversationHandler(emulatorServer: EmulatorRestServer) { + return async (req: Request, res: Response, next: Next): Promise => { const auth = req.header('Authorization'); // TODO: We should not use token as conversation ID @@ -52,14 +52,14 @@ export default function startConversation(botEmulator: BotEmulator) { return JSON.parse(optionsJson).conversationId; }) || uniqueId(); - const { users, conversations } = botEmulator.facilities; + const { users, conversations } = emulatorServer.state; const currentUser = users.usersById(users.currentUserId); let created = false; let conversation = conversations.conversationById(conversationId); if (!conversation) { - conversation = conversations.newConversation(botEmulator, botEndpoint, currentUser, conversationId); + conversation = conversations.newConversation(emulatorServer, botEndpoint, currentUser, conversationId); if (!currentUser) { // New conversations should have a user. Since we don't have one, this is a bug. Report the error diff --git a/packages/app/main/src/server/routes/directLine/handlers/stream.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/stream.spec.ts new file mode 100644 index 000000000..fb864e2dc --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/stream.spec.ts @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { stream } from './stream'; + +describe('stream handler', () => { + it('should send a 501', () => { + const req: any = {}; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + stream(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_IMPLEMENTED); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/stream.ts b/packages/app/main/src/server/routes/directLine/handlers/stream.ts similarity index 82% rename from packages/emulator/core/src/directLine/middleware/stream.ts rename to packages/app/main/src/server/routes/directLine/handlers/stream.ts index 0ae7e765f..be352d230 100644 --- a/packages/emulator/core/src/directLine/middleware/stream.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/stream.ts @@ -32,15 +32,11 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; +export function stream(req: Request, res: Response, next: Next): any { + res.send(HttpStatus.NOT_IMPLEMENTED); + res.end(); -export default function stream(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - res.send(HttpStatus.NOT_IMPLEMENTED); - res.end(); - - next(); - }; + next(); } diff --git a/packages/app/main/src/server/routes/directLine/handlers/upload.spec.ts b/packages/app/main/src/server/routes/directLine/handlers/upload.spec.ts new file mode 100644 index 000000000..5c21abd76 --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/handlers/upload.spec.ts @@ -0,0 +1,153 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { createUploadHandler } from './upload'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('upload handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should be a no-op if the conversation is a transcript', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + state: {}, + }; + const req: any = { + params: { + conversationId: 'conversation1|transcript', + }, + }; + const res: any = { + end: jest.fn(), + }; + const next = jest.fn(); + const upload = createUploadHandler(mockEmulatorServer); + upload(req, res, next); + + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send a 404 if there is no conversation attached to the request', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + state: {}, + }; + const req: any = { + params: { + conversationId: 'conversation1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const upload = createUploadHandler(mockEmulatorServer); + upload(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, 'conversation not found'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should short circuit if the request content is not form data', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + state: {}, + }; + const req: any = { + conversation: {}, + getContentType: jest.fn(() => 'text/plain'), + params: { + conversationId: 'conversation1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const upload = createUploadHandler(mockEmulatorServer); + upload(req, res, next); + + expect(res.send).not.toHaveBeenCalled(); + expect(res.end).not.toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should short circuit if there is no request content', () => { + const mockEmulatorServer: any = { + logger: { + logMessage: jest.fn(), + }, + state: {}, + }; + const req: any = { + conversation: {}, + getContentLength: jest.fn(() => 0), + getContentType: jest.fn(() => 'multipart/form-data'), + isChunked: jest.fn(() => false), + params: { + conversationId: 'conversation1', + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + const upload = createUploadHandler(mockEmulatorServer); + upload(req, res, next); + + expect(res.send).not.toHaveBeenCalled(); + expect(res.end).not.toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + // TODO: At least write test for happy path +}); diff --git a/packages/emulator/core/src/directLine/middleware/upload.ts b/packages/app/main/src/server/routes/directLine/handlers/upload.ts similarity index 85% rename from packages/emulator/core/src/directLine/middleware/upload.ts rename to packages/app/main/src/server/routes/directLine/handlers/upload.ts index de636f3ab..21aced3b4 100644 --- a/packages/emulator/core/src/directLine/middleware/upload.ts +++ b/packages/app/main/src/server/routes/directLine/handlers/upload.ts @@ -37,19 +37,23 @@ import { LogLevel, textItem } from '@bfemulator/sdk-shared'; import { Attachment, AttachmentData } from 'botframework-schema'; import * as Formidable from 'formidable'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import Conversation from '../../facility/conversation'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { BotEndpoint } from '../../../state/botEndpoint'; +import { Conversation } from '../../../state/conversation'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; +import { EmulatorRestServer } from '../../../restServer'; -export default function upload(botEmulator: BotEmulator) { - const { logMessage } = botEmulator.facilities.logger; +export function createUploadHandler(emulatorServer: EmulatorRestServer) { + const { + logger: { logMessage }, + state, + } = emulatorServer; - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { + return (req: Request, res: Response, next: Next): any => { if (req.params.conversationId.includes('transcript')) { res.end(); + next(); return; } @@ -60,11 +64,12 @@ export default function upload(botEmulator: BotEmulator) { res.send(HttpStatus.NOT_FOUND, 'conversation not found'); res.end(); logMessage(req.params.conversationId, textItem(LogLevel.Error, 'Cannot upload file. Conversation not found.')); - + next(); return; } if (req.getContentType() !== 'multipart/form-data' || (req.getContentLength() === 0 && !req.isChunked())) { + next(); return; } @@ -82,7 +87,7 @@ export default function upload(botEmulator: BotEmulator) { uploads = [uploads]; } if (uploads && uploads.length) { - const serviceUrl = await botEmulator.getServiceUrl(botEndpoint.botUrl); + const serviceUrl = await emulatorServer.getServiceUrl(botEndpoint.botUrl); activity.attachments = []; uploads.forEach(upload1 => { const name = (upload1 as any).name || 'file.dat'; @@ -96,7 +101,7 @@ export default function upload(botEmulator: BotEmulator) { originalBase64: new Uint8Array(base64Buf), thumbnailBase64: new Uint8Array(base64Buf), }; - const attachmentId = botEmulator.facilities.attachments.uploadAttachment(attachmentData); + const attachmentId = state.attachments.uploadAttachment(attachmentData); const attachment: Attachment = { name, contentType: type, @@ -109,7 +114,6 @@ export default function upload(botEmulator: BotEmulator) { try { const { activityId, statusCode, response } = await conversation.postActivityToBot(activity, true); - // logNetwork(conversation.conversationId, req, res, `[${activity.type}]`); if (~~statusCode === 0 && ~~statusCode > 300) { res.send(statusCode || HttpStatus.INTERNAL_SERVER_ERROR, await response.text()); res.end(); diff --git a/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.spec.ts b/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.spec.ts new file mode 100644 index 000000000..a16bdd4d5 --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.spec.ts @@ -0,0 +1,118 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createGetBotEndpointMiddleware } from '../handlers/getBotEndpoint'; +import { createJsonBodyParserMiddleware } from '../../utils/jsonBodyParser'; + +import { getActivities } from './handlers/getActivities'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { options } from './handlers/options'; +import { createPostActivityHandler } from './handlers/postActivity'; +import { createReconnectToConversationHandler } from './handlers/reconnectToConversation'; +import { createStartConversationHandler } from './handlers/startConversation'; +import { stream } from './handlers/stream'; +import { createUploadHandler } from './handlers/upload'; +import { mountDirectLineRoutes } from './mountDirectLineRoutes'; + +jest.mock('../handlers/getBotEndpoint', () => ({ createGetBotEndpointMiddleware: jest.fn(() => null) })); +jest.mock('../../utils/jsonBodyParser', () => ({ createJsonBodyParserMiddleware: jest.fn(() => null) })); +jest.mock('./handlers/getActivities', () => ({ getActivities: jest.fn(() => null) })); +jest.mock('./handlers/getConversation', () => ({ createGetConversationHandler: jest.fn(() => null) })); +jest.mock('./handlers/options', () => ({ options: jest.fn(() => null) })); +jest.mock('./handlers/postActivity', () => ({ createPostActivityHandler: jest.fn(() => null) })); +jest.mock('./handlers/reconnectToConversation', () => ({ createReconnectToConversationHandler: jest.fn(() => null) })); +jest.mock('./handlers/startConversation', () => ({ createStartConversationHandler: jest.fn(() => null) })); +jest.mock('./handlers/stream', () => ({ stream: jest.fn(() => null) })); +jest.mock('./handlers/upload', () => ({ createUploadHandler: jest.fn(() => null) })); + +describe('registerRoutes', () => { + it('should register routes', () => { + const get = jest.fn(() => null); + const post = jest.fn(() => null); + const opts = jest.fn(() => null); + const server: any = { + get, + post, + opts, + }; + const emulatorServer: any = { + options: { fetch: () => null }, + server, + state: {}, + }; + const jsonBodyParser = createJsonBodyParserMiddleware(); + const botEndpoint = createGetBotEndpointMiddleware(emulatorServer.state); + const conversation = createGetConversationHandler(emulatorServer.state); + mountDirectLineRoutes(emulatorServer); + + expect(opts).toHaveBeenCalledWith('/v3/directline', options); + + expect(post).toHaveBeenCalledWith( + '/v3/directline/conversations', + botEndpoint, + jsonBodyParser, + createStartConversationHandler(emulatorServer) + ); + + expect(get).toHaveBeenCalledWith( + '/v3/directline/conversations/:conversationId', + botEndpoint, + conversation, + createReconnectToConversationHandler(emulatorServer) + ); + + expect(get).toHaveBeenCalledWith( + '/v3/directline/conversations/:conversationId/activities', + botEndpoint, + conversation, + getActivities + ); + + expect(post).toHaveBeenCalledWith( + '/v3/directline/conversations/:conversationId/activities', + jsonBodyParser, + botEndpoint, + conversation, + createPostActivityHandler(emulatorServer) + ); + + expect(post).toHaveBeenCalledWith( + '/v3/directline/conversations/:conversationId/upload', + botEndpoint, + conversation, + createUploadHandler(emulatorServer) + ); + + expect(get).toHaveBeenCalledWith('/v3/directline/conversations/:conversationId/stream', stream); + }); +}); diff --git a/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.ts b/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.ts new file mode 100644 index 000000000..30fa1683a --- /dev/null +++ b/packages/app/main/src/server/routes/directLine/mountDirectLineRoutes.ts @@ -0,0 +1,87 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createGetBotEndpointMiddleware } from '../handlers/getBotEndpoint'; +import { createJsonBodyParserMiddleware } from '../../utils/jsonBodyParser'; +import { EmulatorRestServer } from '../../restServer'; + +import { getActivities } from './handlers/getActivities'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { options } from './handlers/options'; +import { createPostActivityHandler } from './handlers/postActivity'; +import { createReconnectToConversationHandler } from './handlers/reconnectToConversation'; +import { createStartConversationHandler } from './handlers/startConversation'; +import { stream } from './handlers/stream'; +import { createUploadHandler } from './handlers/upload'; + +export function mountDirectLineRoutes(emulatorServer: EmulatorRestServer) { + const { server, state } = emulatorServer; + const jsonBodyParser = createJsonBodyParserMiddleware(); + const getBotEndpoint = createGetBotEndpointMiddleware(state); + const getConversation = createGetConversationHandler(state); + + server.opts('/v3/directline', options); + + server.post( + '/v3/directline/conversations', + getBotEndpoint, + jsonBodyParser, + createStartConversationHandler(emulatorServer) + ); + + server.get( + '/v3/directline/conversations/:conversationId', + getBotEndpoint, + getConversation, + createReconnectToConversationHandler(emulatorServer) + ); + + server.get('/v3/directline/conversations/:conversationId/activities', getBotEndpoint, getConversation, getActivities); + + server.post( + '/v3/directline/conversations/:conversationId/activities', + jsonBodyParser, + getBotEndpoint, + getConversation, + createPostActivityHandler(emulatorServer) + ); + + server.post( + '/v3/directline/conversations/:conversationId/upload', + getBotEndpoint, + getConversation, + createUploadHandler(emulatorServer) + ); + + server.get('/v3/directline/conversations/:conversationId/stream', stream); +} diff --git a/packages/app/main/src/server/routes/emulator/handlers/addUsers.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/addUsers.spec.ts new file mode 100644 index 000000000..d6fc6f6f3 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/addUsers.spec.ts @@ -0,0 +1,90 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { addUsers } from './addUsers'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('addUsers handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 after adding the users to the conversation', async () => { + const req: any = { + body: JSON.stringify([ + { id: 'user1', name: 'User 1' }, + { id: 'user2', name: 'User 2' }, + ]), + conversation: { + addMember: jest.fn(), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await addUsers(req, res, next); + + expect(req.conversation.addMember).toHaveBeenCalledTimes(2); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + body: JSON.stringify([ + { id: 'user1', name: 'User 1' }, + { id: 'user2', name: 'User 2' }, + ]), + conversation: { + addMember: jest.fn(() => { + throw new Error('Failed to add member.'); + }), + }, + }; + const res: any = {}; + const next = jest.fn(); + await addUsers(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Failed to add member.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/directLine/middleware/getActivities.ts b/packages/app/main/src/server/routes/emulator/handlers/addUsers.ts similarity index 67% rename from packages/emulator/core/src/directLine/middleware/getActivities.ts rename to packages/app/main/src/server/routes/emulator/handlers/addUsers.ts index 5238ac3d3..20f3deeac 100644 --- a/packages/emulator/core/src/directLine/middleware/getActivities.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/addUsers.ts @@ -31,29 +31,27 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +import { ChannelAccount } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import Conversation from '../../facility/conversation'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; -export default function getActivities(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - const conversation: Conversation = (req as any).conversation; +import { ConversationAwareRequest } from './getConversation'; - if (conversation) { - const { activities, watermark } = conversation.getActivitiesSince(Number(req.query.watermark || 0) || 0); - - res.json(HttpStatus.OK, { - activities, - watermark, - }); - } else { - res.send(HttpStatus.NOT_FOUND, 'conversation not found'); +export async function addUsers(req: ConversationAwareRequest, res: Response, next: Next): Promise { + try { + const members: ChannelAccount[] = JSON.parse(req.body || '[]'); + const it = members[Symbol.iterator](); // Node does not support array.values() :( + let member; + while ((member = it.next().value)) { + await req.conversation.addMember(member.id, member.name); } - + res.send(HttpStatus.OK); res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } - next(); - }; + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/contactAdded.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/contactAdded.spec.ts new file mode 100644 index 000000000..531581d1f --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/contactAdded.spec.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { contactAdded } from './contactAdded'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('contactAdded handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 after sending a contact added activity', async () => { + const req: any = { + conversation: { + sendContactAdded: jest.fn(), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await contactAdded(req, res, next); + + expect(req.conversation.sendContactAdded).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + conversation: { + sendContactAdded: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = {}; + const next = jest.fn(); + await contactAdded(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/getPrivateConversationData.ts b/packages/app/main/src/server/routes/emulator/handlers/contactAdded.ts similarity index 75% rename from packages/emulator/core/src/botState/middleware/getPrivateConversationData.ts rename to packages/app/main/src/server/routes/emulator/handlers/contactAdded.ts index 63586a391..48cdd8a6d 100644 --- a/packages/emulator/core/src/botState/middleware/getPrivateConversationData.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/contactAdded.ts @@ -32,20 +32,20 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; -export default function getPrivateConversationData(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - res.send(HttpStatus.OK, (req as any).botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +import { ConversationAwareRequest } from './getConversation'; - next(); - }; +export async function contactAdded(req: ConversationAwareRequest, res: Response, next: Next): Promise { + try { + await req.conversation.sendContactAdded(); + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/contactRemoved.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/contactRemoved.spec.ts new file mode 100644 index 000000000..d6bb4d5e9 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/contactRemoved.spec.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { contactRemoved } from './contactRemoved'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('contactRemoved handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 after sending a contact removed activity', async () => { + const req: any = { + conversation: { + sendContactRemoved: jest.fn(), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await contactRemoved(req, res, next); + + expect(req.conversation.sendContactRemoved).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + conversation: { + sendContactRemoved: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = {}; + const next = jest.fn(); + await contactRemoved(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/getActivityMembers.ts b/packages/app/main/src/server/routes/emulator/handlers/contactRemoved.ts similarity index 74% rename from packages/emulator/core/src/conversations/middleware/getActivityMembers.ts rename to packages/app/main/src/server/routes/emulator/handlers/contactRemoved.ts index 525a5b0cf..1a2c6f36d 100644 --- a/packages/emulator/core/src/conversations/middleware/getActivityMembers.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/contactRemoved.ts @@ -32,20 +32,20 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; -export default function getActivityMembers(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - res.send(HttpStatus.OK, (req as any).conversation.members); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +import { ConversationAwareRequest } from './getConversation'; - next(); - }; +export async function contactRemoved(req: ConversationAwareRequest, res: Response, next: Next): Promise { + try { + await req.conversation.sendContactRemoved(); + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.spec.ts new file mode 100644 index 000000000..e69bdcd4e --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.spec.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { deleteUserData } from './deleteUserData'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('contactRemoved handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 after sending a delete user data activity', async () => { + const req: any = { + conversation: { + sendDeleteUserData: jest.fn(), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await deleteUserData(req, res, next); + + expect(req.conversation.sendDeleteUserData).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + conversation: { + sendDeleteUserData: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = {}; + const next = jest.fn(); + await deleteUserData(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.ts b/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.ts new file mode 100644 index 000000000..210106543 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/deleteUserData.ts @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Response } from 'restify'; + +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; + +import { ConversationAwareRequest } from './getConversation'; + +export async function deleteUserData(req: ConversationAwareRequest, res: Response, next: Next): Promise { + try { + await req.conversation.sendDeleteUserData(); + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); +} diff --git a/packages/emulator/core/src/conversations/middleware/getConversationMembers.ts b/packages/app/main/src/server/routes/emulator/handlers/getConversation.spec.ts similarity index 61% rename from packages/emulator/core/src/conversations/middleware/getConversationMembers.ts rename to packages/app/main/src/server/routes/emulator/handlers/getConversation.spec.ts index 150706411..7a104053a 100644 --- a/packages/emulator/core/src/conversations/middleware/getConversationMembers.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/getConversation.spec.ts @@ -31,23 +31,34 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createAPIException } from '../../../utils/createResponse/createAPIException'; + +import { createGetConversationHandler } from './getConversation'; + +describe('getConversation handler', () => { + it('should send an error response if the conversation is not found', () => { + const mockServerState: any = { + conversations: { + conversationById: jest.fn(() => undefined), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = {}; + const next = jest.fn(); + const getConversation = createGetConversationHandler(mockServerState); -// get members of a conversation -export default function getConversationMembers(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { try { - // look up conversation - res.send(HttpStatus.OK, (req as any).conversation.members); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); + getConversation(req, res, next); + expect(true).toBe(false); // ensure catch is hit + } catch (e) { + expect(e).toEqual(createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found')); } - - next(); - }; -} + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/fetchConversation.ts b/packages/app/main/src/server/routes/emulator/handlers/getConversation.ts similarity index 77% rename from packages/emulator/core/src/emulator/middleware/fetchConversation.ts rename to packages/app/main/src/server/routes/emulator/handlers/getConversation.ts index 73fe777ad..cd7004ae4 100644 --- a/packages/emulator/core/src/emulator/middleware/fetchConversation.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/getConversation.ts @@ -35,17 +35,17 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import Conversation from '../../facility/conversation'; +import { createAPIException } from '../../../utils/createResponse/createAPIException'; +import { Conversation } from '../../../state/conversation'; +import { ServerState } from '../../../state/serverState'; -export interface ConversationAware extends Request { +export interface ConversationAwareRequest extends Request { conversation: Conversation; } -export default function fetchConversation(botEmulator: BotEmulator) { - return (req: ConversationAware, res: Response, next: Next): any => { - const conversation = botEmulator.facilities.conversations.conversationById(req.params.conversationId); +export function createGetConversationHandler(state: ServerState) { + return (req: ConversationAwareRequest, res: Response, next: Next): any => { + const conversation = state.conversations.conversationById(req.params.conversationId); if (!conversation) { throw createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found'); @@ -53,6 +53,6 @@ export default function fetchConversation(botEmulator: BotEmulator) { req.conversation = conversation; - return next(); + next(); }; } diff --git a/packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.spec.ts new file mode 100644 index 000000000..5166b2b20 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.spec.ts @@ -0,0 +1,133 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { ErrorCodes } from '@bfemulator/app-shared'; + +import { createAPIException } from '../../../utils/createResponse/createAPIException'; + +import { createGetConversationEndpointHandler } from './getConversationEndpoint'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('getConversationEndpoint handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should throw an exception if the conversation is not found', () => { + const mockServerState: any = { + conversations: { + conversationById: jest.fn(() => undefined), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = {}; + const next = jest.fn(); + const getConversationEndpoint = createGetConversationEndpointHandler(mockServerState); + + try { + getConversationEndpoint(req, res, next); + expect(true).toBe(false); // ensure catch is hit + } catch (e) { + expect(e).toEqual(createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found')); + } + expect(next).not.toHaveBeenCalled(); + }); + + it('should send a 200 with the bot endpoint', () => { + const mockConversation = { + botEndpoint: { + url: 'http://some.url.com/api/messages', + }, + }; + const mockServerState: any = { + conversations: { + conversationById: jest.fn(() => mockConversation), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + json: jest.fn(), + }; + const next = jest.fn(); + const getConversationEndpoint = createGetConversationEndpointHandler(mockServerState); + getConversationEndpoint(req, res, next); + + expect(res.json).toHaveBeenCalledWith(HttpStatus.OK, mockConversation.botEndpoint); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', () => { + const mockConversation = { + botEndpoint: { + url: 'http://some.url.com/api/messages', + }, + }; + const mockServerState: any = { + conversations: { + conversationById: jest.fn(() => mockConversation), + }, + }; + const req: any = { + params: { + conversationId: 'convo1', + }, + }; + const res: any = { + end: jest.fn(), + json: jest.fn(() => { + throw new Error('Something went wrong.'); + }), + }; + const next = jest.fn(); + const getConversationEndpoint = createGetConversationEndpointHandler(mockServerState); + getConversationEndpoint(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/getConversationEndpoint.ts b/packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.ts similarity index 82% rename from packages/emulator/core/src/emulator/middleware/getConversationEndpoint.ts rename to packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.ts index a80818098..4f100e629 100644 --- a/packages/emulator/core/src/emulator/middleware/getConversationEndpoint.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/getConversationEndpoint.ts @@ -35,18 +35,18 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import createAPIException from '../../utils/createResponse/apiException'; -import Conversation from '../../facility/conversation'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { createAPIException } from '../../../utils/createResponse/createAPIException'; +import { Conversation } from '../../../state/conversation'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; +import { ServerState } from '../../../state/serverState'; export interface ConversationAware extends Request { conversation: Conversation; } -export default function fetchConversation(botEmulator: BotEmulator) { +export function createGetConversationEndpointHandler(state: ServerState) { return (req: ConversationAware, res: Response, next: Next): any => { - const conversation = botEmulator.facilities.conversations.conversationById(req.params.conversationId); + const conversation = state.conversations.conversationById(req.params.conversationId); if (!conversation) { throw createAPIException(HttpStatus.NOT_FOUND, ErrorCodes.BadArgument, 'conversation not found'); diff --git a/packages/app/main/src/server/routes/emulator/handlers/getUsers.ts b/packages/app/main/src/server/routes/emulator/handlers/getUsers.ts new file mode 100644 index 000000000..1aea3691a --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/getUsers.ts @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Response } from 'restify'; + +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; + +import { ConversationAwareRequest } from './getConversation'; + +export function getUsers(req: ConversationAwareRequest, res: Response, next: Next): any { + try { + res.json(HttpStatus.OK, req.conversation.members); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); +} diff --git a/packages/app/main/src/server/routes/emulator/handlers/paymentComplete.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/paymentComplete.spec.ts new file mode 100644 index 000000000..759f99c57 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/paymentComplete.spec.ts @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { paymentComplete } from './paymentComplete'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('paymentComplete handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with the response body', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendPaymentCompleteOperation: jest.fn().mockResolvedValueOnce('some response'), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await paymentComplete(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, 'some response'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendPaymentCompleteOperation: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await paymentComplete(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(res.send).toHaveBeenCalledWith(HttpStatus.INTERNAL_SERVER_ERROR); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/setPrivateConversationData.ts b/packages/app/main/src/server/routes/emulator/handlers/paymentComplete.ts similarity index 64% rename from packages/emulator/core/src/botState/middleware/setPrivateConversationData.ts rename to packages/app/main/src/server/routes/emulator/handlers/paymentComplete.ts index 206ba5c93..8c5ca1726 100644 --- a/packages/emulator/core/src/botState/middleware/setPrivateConversationData.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/paymentComplete.ts @@ -31,29 +31,25 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { BotData } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; -export default function setPrivateConversationData(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const botData = botEmulator.facilities.botState.setBotData( - req.params.channelId, - req.params.conversationId, - req.params.userId, - req.body as BotData - ); +import { ConversationAwareRequest } from './getConversation'; - res.send(HttpStatus.OK, botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +export async function paymentComplete(req: ConversationAwareRequest, res: Response, next: Next): Promise { + const { checkoutSession, request, shippingAddress, shippingOptionId, payerPhone, payerEmail } = req.body[0]; + const args = [checkoutSession, request, shippingAddress, shippingOptionId, payerEmail, payerPhone]; - next(); - }; + try { + const response = await req.conversation.sendPaymentCompleteOperation.apply(req.conversation, args); + res.send(HttpStatus.OK, response); + } catch (err) { + sendErrorResponse(req, res, next, err); + res.send(HttpStatus.INTERNAL_SERVER_ERROR); + } + res.end(); + + next(); } diff --git a/packages/emulator/core/src/emulator/middleware/removeUsers.ts b/packages/app/main/src/server/routes/emulator/handlers/ping.spec.ts similarity index 54% rename from packages/emulator/core/src/emulator/middleware/removeUsers.ts rename to packages/app/main/src/server/routes/emulator/handlers/ping.spec.ts index 379ddfc8f..8ba807fd3 100644 --- a/packages/emulator/core/src/emulator/middleware/removeUsers.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/ping.spec.ts @@ -32,34 +32,48 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; +import { ping } from './ping'; -export default function removeUsers(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - // try { - // let members: ChannelAccount[] = req.body; +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); - // if (!members) { - // members = [...req['conversation'].members]; - // members = members.filter(member => member.id !== - // botEmulator.facilities.users.currentUserId && member.id !== botEmulator.botId); - // members = members.slice(0); - // } +describe('ping handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); - // members.forEach(member => { - // req['conversation'].removeMember(member.id); - // }); + it('should send a 200 after sending a ping activity', async () => { + const req: any = { + conversation: { + sendPing: jest.fn().mockResolvedValueOnce(undefined), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await ping(req, res, next); - // res.send(HttpStatus.OK); - // res.end(); - // } catch (err) { - // sendErrorResponse(req, res, next, err); - // } + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); - res.send(HttpStatus.NOT_IMPLEMENTED); + it('should send an error response if something goes wrong', async () => { + const req: any = { + conversation: { + sendPing: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = {}; + const next = jest.fn(); + await ping(req, res, next); - next(); - }; -} + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/emulator/handlers/ping.ts b/packages/app/main/src/server/routes/emulator/handlers/ping.ts new file mode 100644 index 000000000..f2fdbac35 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/ping.ts @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Response } from 'restify'; + +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; + +import { ConversationAwareRequest } from './getConversation'; + +export async function ping(req: ConversationAwareRequest, res: Response, next: Next): Promise { + try { + await req.conversation.sendPing(); + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); +} diff --git a/packages/app/main/src/server/routes/emulator/handlers/removeUsers.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/removeUsers.spec.ts new file mode 100644 index 000000000..715d99d4d --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/removeUsers.spec.ts @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { removeUsers } from './removeUsers'; + +describe('removeUsers handler', () => { + it('should send a 501', () => { + const req: any = {}; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + removeUsers(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.NOT_IMPLEMENTED); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/conversations/middleware/deleteActivity.ts b/packages/app/main/src/server/routes/emulator/handlers/removeUsers.ts similarity index 66% rename from packages/emulator/core/src/conversations/middleware/deleteActivity.ts rename to packages/app/main/src/server/routes/emulator/handlers/removeUsers.ts index e28ff6072..ddc279185 100644 --- a/packages/emulator/core/src/conversations/middleware/deleteActivity.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/removeUsers.ts @@ -32,25 +32,31 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Request, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import ConversationAPIPathParameters from '../conversationAPIPathParameters'; +export function removeUsers(req: Request, res: Response, next: Next): any { + // try { + // let members: ChannelAccount[] = req.body; -export default function deleteActivity(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - const conversationParameters: ConversationAPIPathParameters = req.params; + // if (!members) { + // members = [...req['conversation'].members]; + // members = members.filter(member => member.id !== + // botEmulator.facilities.users.currentUserId && member.id !== botEmulator.botId); + // members = members.slice(0); + // } - try { - (req as any).conversation.deleteActivity(conversationParameters.activityId); + // members.forEach(member => { + // req['conversation'].removeMember(member.id); + // }); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + // res.send(HttpStatus.OK); + // res.end(); + // } catch (err) { + // sendErrorResponse(req, res, next, err); + // } - next(); - }; + res.send(HttpStatus.NOT_IMPLEMENTED); + res.end(); + + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.spec.ts new file mode 100644 index 000000000..e68ca0613 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.spec.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { sendTokenResponse } from './sendTokenResponse'; + +describe('sendTokenResponse handler', () => { + it('should send a 200 if the result of sending the token was a 200', async () => { + const req: any = { + body: [{ token: 'someToken', connectionName: 'conn1' }], + conversation: { + sendTokenResponse: jest.fn().mockResolvedValueOnce({ statusCode: HttpStatus.OK }), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await sendTokenResponse(req, res, next); + + const body = req.body[0]; + expect(req.conversation.sendTokenResponse).toHaveBeenCalledWith(body.connectionName, body.token, true); + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, body); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send the status code if the result of sending the token was not a 200', async () => { + const req: any = { + body: [{ token: 'someToken', connectionName: 'conn1' }], + conversation: { + sendTokenResponse: jest.fn().mockResolvedValueOnce({ statusCode: HttpStatus.BAD_REQUEST }), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await sendTokenResponse(req, res, next); + + const body = req.body[0]; + expect(req.conversation.sendTokenResponse).toHaveBeenCalledWith(body.connectionName, body.token, true); + expect(res.send).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/emulator/middleware/getUsers.ts b/packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.ts similarity index 72% rename from packages/emulator/core/src/emulator/middleware/getUsers.ts rename to packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.ts index 48dcfb44e..0a09d33be 100644 --- a/packages/emulator/core/src/emulator/middleware/getUsers.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/sendTokenResponse.ts @@ -32,22 +32,24 @@ // import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; +import { Next, Response } from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { ConversationAwareRequest } from './getConversation'; -import { ConversationAware } from './fetchConversation'; +export async function sendTokenResponse(req: ConversationAwareRequest, res: Response, next: Next): Promise { + const body: { + token: string; + connectionName: string; + } = req.body[0]; -export default function getUsers(_botEmulator: BotEmulator) { - return (req: ConversationAware, res: Restify.Response, next: Restify.Next): any => { - try { - res.json(HttpStatus.OK, req.conversation.members); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } + const { statusCode } = await req.conversation.sendTokenResponse(body.connectionName, body.token, true); - next(); - }; + if (statusCode === HttpStatus.OK) { + res.send(HttpStatus.OK, body); + } else { + res.send(statusCode); + } + res.end(); + + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/sendTyping.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/sendTyping.spec.ts new file mode 100644 index 000000000..df239d6e5 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/sendTyping.spec.ts @@ -0,0 +1,79 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { sendTyping } from './sendTyping'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('sendTyping handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 after sending a ping activity', async () => { + const req: any = { + conversation: { + sendTyping: jest.fn().mockResolvedValueOnce(undefined), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await sendTyping(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + conversation: { + sendTyping: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = {}; + const next = jest.fn(); + await sendTyping(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/emulator/core/src/botState/middleware/getUserData.ts b/packages/app/main/src/server/routes/emulator/handlers/sendTyping.ts similarity index 77% rename from packages/emulator/core/src/botState/middleware/getUserData.ts rename to packages/app/main/src/server/routes/emulator/handlers/sendTyping.ts index 1aedfe9d2..37c9a713d 100644 --- a/packages/emulator/core/src/botState/middleware/getUserData.ts +++ b/packages/app/main/src/server/routes/emulator/handlers/sendTyping.ts @@ -34,18 +34,22 @@ import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; -export default function getUserData(_botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - res.send(HttpStatus.OK, (req as any).botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } +import { ConversationAwareRequest } from './getConversation'; - next(); - }; +export async function sendTyping( + req: ConversationAwareRequest, + res: Restify.Response, + next: Restify.Next +): Promise { + try { + await req.conversation.sendTyping(); + res.send(HttpStatus.OK); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + + next(); } diff --git a/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.spec.ts new file mode 100644 index 000000000..56757109f --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.spec.ts @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { updateShippingAddress } from './updateShippingAddress'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('updateShippingAddress handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with the response body', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendUpdateShippingAddressOperation: jest.fn().mockResolvedValueOnce({ + json: jest.fn().mockResolvedValueOnce('json payload'), + }), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await updateShippingAddress(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, 'json payload'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendUpdateShippingAddressOperation: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await updateShippingAddress(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.ts b/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.ts new file mode 100644 index 000000000..dc68f3223 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/updateShippingAddress.ts @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Response } from 'restify'; + +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; + +import { ConversationAwareRequest } from './getConversation'; + +export async function updateShippingAddress(req: ConversationAwareRequest, res: Response, next: Next): Promise { + const { checkoutSession, request, shippingAddress, shippingOptionId } = req.body[0]; + const args = [checkoutSession, request, shippingAddress, shippingOptionId]; + try { + const response = await req.conversation.sendUpdateShippingAddressOperation.apply(req.conversation, args); + const json = await response.json(); + res.send(HttpStatus.OK, json); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + next(); +} diff --git a/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.spec.ts b/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.spec.ts new file mode 100644 index 000000000..978033bb1 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.spec.ts @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; + +import { updateShippingOption } from './updateShippingOption'; + +const mockSendErrorResponse = jest.fn(); +jest.mock('../../../utils/sendErrorResponse', () => ({ + sendErrorResponse: (...args) => mockSendErrorResponse(...args), +})); + +describe('updateShippingOption handler', () => { + beforeEach(() => { + mockSendErrorResponse.mockClear(); + }); + + it('should send a 200 with the response body', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendUpdateShippingOptionOperation: jest.fn().mockResolvedValueOnce({ + json: jest.fn().mockResolvedValueOnce('json payload'), + }), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await updateShippingOption(req, res, next); + + expect(res.send).toHaveBeenCalledWith(HttpStatus.OK, 'json payload'); + expect(res.end).toHaveBeenCalled(); + expect(next).toHaveBeenCalled(); + }); + + it('should send an error response if something goes wrong', async () => { + const req: any = { + body: [ + { + checkoutSession: {}, + request: {}, + shippingAddress: {}, + shippingOptionId: 'someId', + }, + ], + conversation: { + sendUpdateShippingOptionOperation: jest.fn().mockRejectedValueOnce(new Error('Something went wrong.')), + }, + }; + const res: any = { + end: jest.fn(), + send: jest.fn(), + }; + const next = jest.fn(); + await updateShippingOption(req, res, next); + + expect(mockSendErrorResponse).toHaveBeenCalledWith(req, res, next, new Error('Something went wrong.')); + expect(next).toHaveBeenCalled(); + }); +}); diff --git a/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.ts b/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.ts new file mode 100644 index 000000000..c0d3eb726 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/handlers/updateShippingOption.ts @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import * as HttpStatus from 'http-status-codes'; +import { Next, Response } from 'restify'; + +import { sendErrorResponse } from '../../../utils/sendErrorResponse'; + +import { ConversationAwareRequest } from './getConversation'; + +export async function updateShippingOption(req: ConversationAwareRequest, res: Response, next: Next): Promise { + const { checkoutSession, request, shippingAddress, shippingOptionId } = req.body[0]; + const args = [checkoutSession, request, shippingAddress, shippingOptionId]; + try { + const response = await req.conversation.sendUpdateShippingOptionOperation.apply(req.conversation, args); + const json = await response.json(); + res.send(HttpStatus.OK, json); + res.end(); + } catch (err) { + sendErrorResponse(req, res, next, err); + } + next(); +} diff --git a/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.spec.ts b/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.spec.ts new file mode 100644 index 000000000..f3920314d --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.spec.ts @@ -0,0 +1,128 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createJsonBodyParserMiddleware } from '../../utils/jsonBodyParser'; + +import { addUsers } from './handlers/addUsers'; +import { contactAdded } from './handlers/contactAdded'; +import { contactRemoved } from './handlers/contactRemoved'; +import { deleteUserData } from './handlers/deleteUserData'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { getUsers } from './handlers/getUsers'; +import { paymentComplete } from './handlers/paymentComplete'; +import { ping } from './handlers/ping'; +import { removeUsers } from './handlers/removeUsers'; +import { sendTokenResponse } from './handlers/sendTokenResponse'; +import { sendTyping } from './handlers/sendTyping'; +import { updateShippingAddress } from './handlers/updateShippingAddress'; +import { updateShippingOption } from './handlers/updateShippingOption'; +import { mountEmulatorRoutes } from './mountEmulatorRoutes'; + +jest.mock('../../utils/jsonBodyParser', () => ({ createJsonBodyParserMiddleware: jest.fn(() => null) })); +jest.mock('./handlers/addUsers', () => ({ addUsers: jest.fn(() => null) })); +jest.mock('./handlers/contactAdded', () => ({ contactAdded: jest.fn(() => null) })); +jest.mock('./handlers/contactRemoved', () => ({ contactRemoved: jest.fn(() => null) })); +jest.mock('./handlers/deleteUserData', () => ({ deleteUserData: jest.fn(() => null) })); +jest.mock('./handlers/getConversation', () => ({ createGetConversationHandler: jest.fn(() => null) })); +jest.mock('./handlers/getUsers', () => ({ getUsers: jest.fn(() => null) })); +jest.mock('./handlers/paymentComplete', () => ({ paymentComplete: jest.fn(() => null) })); +jest.mock('./handlers/ping', () => ({ ping: jest.fn(() => null) })); +jest.mock('./handlers/removeUsers', () => ({ removeUsers: jest.fn(() => null) })); +jest.mock('./handlers/sendTokenResponse', () => ({ sendTokenResponse: jest.fn(() => null) })); +jest.mock('./handlers/sendTyping', () => ({ sendTyping: jest.fn(() => null) })); +jest.mock('./handlers/updateShippingAddress', () => ({ updateShippingAddress: jest.fn(() => null) })); +jest.mock('./handlers/updateShippingOption', () => ({ updateShippingOption: jest.fn(() => null) })); + +describe('mountEmulatorRoutes', () => { + it('should mount the routes', () => { + const get = jest.fn(() => null); + const post = jest.fn(() => null); + const del = jest.fn(() => null); + const server: any = { + get, + post, + del, + }; + const emulatorServer: any = { + options: { fetch: () => null }, + server, + state: {}, + }; + const getConversation = createGetConversationHandler(emulatorServer.state); + const jsonBodyParser = createJsonBodyParserMiddleware(); + mountEmulatorRoutes(emulatorServer); + + expect(get).toHaveBeenCalledWith('/emulator/:conversationId/users', getConversation, getUsers); + + expect(post).toHaveBeenCalledWith('/emulator/:conversationId/users', jsonBodyParser, getConversation, addUsers); + + expect(del).toHaveBeenCalledWith('/emulator/:conversationId/users', getConversation, removeUsers); + + expect(post).toHaveBeenCalledWith('/emulator/:conversationId/contacts', getConversation, contactAdded); + + expect(del).toHaveBeenCalledWith('/emulator/:conversationId/contacts', getConversation, contactRemoved); + + expect(post).toHaveBeenCalledWith('/emulator/:conversationId/typing', getConversation, sendTyping); + + expect(post).toHaveBeenCalledWith('/emulator/:conversationId/ping', getConversation, ping); + + expect(del).toHaveBeenCalledWith('/emulator/:conversationId/userdata', getConversation, deleteUserData); + + expect(post).toHaveBeenCalledWith( + '/emulator/:conversationId/invoke/updateShippingAddress', + jsonBodyParser, + getConversation, + updateShippingAddress + ); + + expect(post).toHaveBeenCalledWith( + '/emulator/:conversationId/invoke/updateShippingOption', + jsonBodyParser, + getConversation, + updateShippingOption + ); + + expect(post).toHaveBeenCalledWith( + '/emulator/:conversationId/invoke/paymentComplete', + jsonBodyParser, + getConversation, + paymentComplete + ); + + expect(post).toHaveBeenCalledWith( + '/emulator/:conversationId/invoke/sendTokenResponse', + jsonBodyParser, + sendTokenResponse + ); + }); +}); diff --git a/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.ts b/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.ts new file mode 100644 index 000000000..fcad74858 --- /dev/null +++ b/packages/app/main/src/server/routes/emulator/mountEmulatorRoutes.ts @@ -0,0 +1,98 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { createJsonBodyParserMiddleware } from '../../utils/jsonBodyParser'; +import { EmulatorRestServer } from '../../restServer'; + +import { addUsers } from './handlers/addUsers'; +import { contactAdded } from './handlers/contactAdded'; +import { contactRemoved } from './handlers/contactRemoved'; +import { deleteUserData } from './handlers/deleteUserData'; +import { createGetConversationHandler } from './handlers/getConversation'; +import { getUsers } from './handlers/getUsers'; +import { paymentComplete } from './handlers/paymentComplete'; +import { ping } from './handlers/ping'; +import { removeUsers } from './handlers/removeUsers'; +import { sendTokenResponse } from './handlers/sendTokenResponse'; +import { sendTyping } from './handlers/sendTyping'; +import { updateShippingAddress } from './handlers/updateShippingAddress'; +import { updateShippingOption } from './handlers/updateShippingOption'; +import { createGetConversationEndpointHandler } from './handlers/getConversationEndpoint'; + +export function mountEmulatorRoutes(emulatorServer: EmulatorRestServer) { + const { server, state } = emulatorServer; + const getConversation = createGetConversationHandler(state); + const jsonBodyParser = createJsonBodyParserMiddleware(); + + server.get('/emulator/:conversationId/endpoint', createGetConversationEndpointHandler(state)); + + server.get('/emulator/:conversationId/users', getConversation, getUsers); + + server.post('/emulator/:conversationId/users', jsonBodyParser, getConversation, addUsers); + + server.del('/emulator/:conversationId/users', getConversation, removeUsers); + + server.post('/emulator/:conversationId/contacts', getConversation, contactAdded); + + server.del('/emulator/:conversationId/contacts', getConversation, contactRemoved); + + server.post('/emulator/:conversationId/typing', getConversation, sendTyping); + + server.post('/emulator/:conversationId/ping', getConversation, ping); + + server.del('/emulator/:conversationId/userdata', getConversation, deleteUserData); + + server.post( + '/emulator/:conversationId/invoke/updateShippingAddress', + jsonBodyParser, + getConversation, + updateShippingAddress + ); + + server.post( + '/emulator/:conversationId/invoke/updateShippingOption', + jsonBodyParser, + getConversation, + updateShippingOption + ); + + server.post('/emulator/:conversationId/invoke/paymentComplete', jsonBodyParser, getConversation, paymentComplete); + + server.post('/emulator/:conversationId/invoke/sendTokenResponse', jsonBodyParser, sendTokenResponse); + + server.get('/emulator/users', (req, res, next) => { + res.send(200, state.users); + res.end(); + next(); + }); +} diff --git a/packages/emulator/core/src/utils/botFrameworkAuthentication.spec.ts b/packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.spec.ts similarity index 97% rename from packages/emulator/core/src/utils/botFrameworkAuthentication.spec.ts rename to packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.spec.ts index 68afe34fa..d59e9a2e0 100644 --- a/packages/emulator/core/src/utils/botFrameworkAuthentication.spec.ts +++ b/packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.spec.ts @@ -31,16 +31,21 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { usGovernmentAuthentication, authentication, v32Authentication, v31Authentication } from '../authEndpoints'; +import { + usGovernmentAuthentication, + authentication, + v32Authentication, + v31Authentication, +} from '../../constants/authEndpoints'; -import createBotFrameworkAuthenticationMiddleware from './botFrameworkAuthentication'; +import { createBotFrameworkAuthenticationMiddleware } from './botFrameworkAuthentication'; const mockGetKey = jest.fn().mockResolvedValue(`openIdMetadataKey`); -jest.mock('./openIdMetadata', () => { - return jest.fn().mockImplementation(() => ({ +jest.mock('../../utils/openIdMetadata', () => ({ + OpenIdMetadata: jest.fn().mockImplementation(() => ({ getKey: mockGetKey, - })); -}); + })), +})); let mockDecode; let mockVerify; diff --git a/packages/emulator/core/src/utils/botFrameworkAuthentication.ts b/packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.ts similarity index 95% rename from packages/emulator/core/src/utils/botFrameworkAuthentication.ts rename to packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.ts index c4500f86d..8dcec3807 100644 --- a/packages/emulator/core/src/utils/botFrameworkAuthentication.ts +++ b/packages/app/main/src/server/routes/handlers/botFrameworkAuthentication.ts @@ -34,11 +34,15 @@ import * as jwt from 'jsonwebtoken'; import * as Restify from 'restify'; -import { authentication, usGovernmentAuthentication, v31Authentication, v32Authentication } from '../authEndpoints'; - -import OpenIdMetadata from './openIdMetadata'; - -export default function createBotFrameworkAuthenticationMiddleware(fetch: any) { +import { + authentication, + usGovernmentAuthentication, + v31Authentication, + v32Authentication, +} from '../../constants/authEndpoints'; +import { OpenIdMetadata } from '../../utils/openIdMetadata'; + +export function createBotFrameworkAuthenticationMiddleware(fetch: any) { const openIdMetadata = new OpenIdMetadata(fetch, authentication.openIdMetadata); const usGovOpenIdMetadata = new OpenIdMetadata(fetch, usGovernmentAuthentication.openIdMetadata); diff --git a/packages/emulator/core/src/middleware/getBotEndpoint.spec.ts b/packages/app/main/src/server/routes/handlers/getBotEndpoint.spec.ts similarity index 82% rename from packages/emulator/core/src/middleware/getBotEndpoint.spec.ts rename to packages/app/main/src/server/routes/handlers/getBotEndpoint.spec.ts index cda407f75..b91836da0 100644 --- a/packages/emulator/core/src/middleware/getBotEndpoint.spec.ts +++ b/packages/app/main/src/server/routes/handlers/getBotEndpoint.spec.ts @@ -30,13 +30,14 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import Endpoints from '../facility/endpointSet'; -import getBotEndpoint from './getBotEndpoint'; +import { EndpointSet } from '../../state/endpointSet'; + +import { createGetBotEndpointMiddleware } from './getBotEndpoint'; describe('The getBotEndpoint', () => { - const mockEmulator = { - facilities: {}, + const mockServerState = { + endpoints: {}, } as any; const mockNext = function() { @@ -47,7 +48,7 @@ describe('The getBotEndpoint', () => { }; beforeEach(() => { - mockEmulator.facilities.endpoints = new Endpoints({}); + mockServerState.endpoints = new EndpointSet(() => null); }); it('should append the bot endpoint to the request when an Authorization header is present', () => { @@ -57,9 +58,9 @@ describe('The getBotEndpoint', () => { header: () => `Bearer ${mockToken}`, } as any; - mockEmulator.facilities.endpoints.push(mockToken, mockEndpoint); + mockServerState.endpoints.set(mockToken, mockEndpoint); - const route = getBotEndpoint(mockEmulator as any); + const route = createGetBotEndpointMiddleware(mockServerState as any); route(mockReq as any, {} as any, mockNext); expect(mockReq.botEndpoint.id).toBe(mockEndpoint.id); @@ -67,13 +68,13 @@ describe('The getBotEndpoint', () => { it('should append the default endpoint when no auth header is preset', () => { const mockEndpoint = { id: '123' } as any; - mockEmulator.facilities.endpoints.push('123', mockEndpoint); + mockServerState.endpoints.set('123', mockEndpoint); const mockReq = { header: () => '', } as any; - const route = getBotEndpoint(mockEmulator as any); + const route = createGetBotEndpointMiddleware(mockServerState as any); route(mockReq, {} as any, mockNext); expect(mockReq.botEndpoint.id).toBe(mockEndpoint.id); diff --git a/packages/emulator/core/src/middleware/getBotEndpoint.ts b/packages/app/main/src/server/routes/handlers/getBotEndpoint.ts similarity index 91% rename from packages/emulator/core/src/middleware/getBotEndpoint.ts rename to packages/app/main/src/server/routes/handlers/getBotEndpoint.ts index cc5e110b2..29447ff46 100644 --- a/packages/emulator/core/src/middleware/getBotEndpoint.ts +++ b/packages/app/main/src/server/routes/handlers/getBotEndpoint.ts @@ -33,12 +33,12 @@ import * as Restify from 'restify'; -import { BotEmulator } from '../botEmulator'; +import { ServerState } from '../../state/serverState'; -export default function getBotEndpoint(botEmulator: BotEmulator) { +export function createGetBotEndpointMiddleware(serverState: ServerState) { return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { const auth = req.header('Authorization'); - const { endpoints } = botEmulator.facilities; + const { endpoints } = serverState; // TODO: We should not use token as conversation ID const tokenMatch = /Bearer\s+(.+)/.exec(auth) || []; (req as any).botEndpoint = endpoints.get(tokenMatch[1]) || endpoints.getDefault(); diff --git a/packages/emulator/core/src/utils/stripEmptyBearerToken.spec.ts b/packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.spec.ts similarity index 89% rename from packages/emulator/core/src/utils/stripEmptyBearerToken.spec.ts rename to packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.spec.ts index b6865fd88..bffd7be87 100644 --- a/packages/emulator/core/src/utils/stripEmptyBearerToken.spec.ts +++ b/packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.spec.ts @@ -31,24 +31,22 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import stripEmptyBearerToken from './stripEmptyBearerToken'; +import { stripEmptyBearerTokenMiddleware } from './stripEmptyBearerToken'; describe('stripEmptyBearerToken', () => { it('should create a middleware that strips the empty bearer token', () => { - const middleware = stripEmptyBearerToken(); const next = jest.fn(() => null); const request = { headers: { authorization: 'Bearer' } }; - middleware(request, null, next); + stripEmptyBearerTokenMiddleware(request, null, next); expect(request.headers.authorization).toBe(undefined); expect(next).toHaveBeenCalled(); }); it('should not attempt to strip the auth header if it does not exist', () => { - const middleware = stripEmptyBearerToken(); const next = jest.fn(() => null); const request = { headers: { authorization: null } }; - middleware(request, null, next); + stripEmptyBearerTokenMiddleware(request, null, next); expect(request.headers.authorization).toBe(null); expect(next).toHaveBeenCalled(); diff --git a/packages/emulator/core/src/utils/stripEmptyBearerToken.ts b/packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.ts similarity index 83% rename from packages/emulator/core/src/utils/stripEmptyBearerToken.ts rename to packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.ts index 29cee7464..bad499350 100644 --- a/packages/emulator/core/src/utils/stripEmptyBearerToken.ts +++ b/packages/app/main/src/server/routes/handlers/stripEmptyBearerToken.ts @@ -35,18 +35,17 @@ // our csx environment will generate a Authorization token of "Bearer" // This confuses the auth system, we either want no auth header for local debug // or we want a full bearer token. This parser strips off the Auth header if it is just "Bearer" -export default function createStripEmptyBearerTokenMiddleware() { - return (req, res, next) => { - if (!req.headers.authorization) { - return next(); - } +export function stripEmptyBearerTokenMiddleware(req, res, next) { + if (!req.headers.authorization) { + next(); + return; + } - const pieces = req.headers.authorization.split(' ', 2); + const pieces = req.headers.authorization.split(' ', 2); - if (pieces.length === 1 && pieces[0] === 'Bearer') { - delete req.headers.authorization; - } + if (pieces.length === 1 && pieces[0] === 'Bearer') { + delete req.headers.authorization; + } - return next(); - }; + next(); } diff --git a/packages/app/main/src/server/routes/mountAllRoutes.spec.ts b/packages/app/main/src/server/routes/mountAllRoutes.spec.ts new file mode 100644 index 000000000..992beba73 --- /dev/null +++ b/packages/app/main/src/server/routes/mountAllRoutes.spec.ts @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +import { mountAttachmentsRoutes } from './channel/attachments/mountAttachmentsRoutes'; +import { mountBotStateRoutes } from './channel/botState/mountBotStateRoutes'; +import { mountConversationsRoutes } from './channel/conversations/mountConversationsRoutes'; +import { mountDirectLineRoutes } from './directLine/mountDirectLineRoutes'; +import { mountEmulatorRoutes } from './emulator/mountEmulatorRoutes'; +import { mountSessionRoutes } from './channel/session/mountSessionRoutes'; +import { mountUserTokenRoutes } from './channel/userToken/mountUserTokenRoutes'; +import { mountAllRoutes } from './mountAllRoutes'; + +const mockMountAttachmentsRoutes = jest.fn(); +jest.mock('./channel/attachments/mountAttachmentsRoutes', () => ({ + mountAttachmentsRoutes: server => mockMountAttachmentsRoutes(server), +})); +const mockMountBotStateRoutes = jest.fn(); +jest.mock('./channel/botState/mountBotStateRoutes', () => ({ + mountBotStateRoutes: server => mockMountBotStateRoutes(server), +})); +const mockMountConversationsRoutes = jest.fn(); +jest.mock('./channel/conversations/mountConversationsRoutes', () => ({ + mountConversationsRoutes: server => mockMountConversationsRoutes(server), +})); +const mockMountDirectLineRoutes = jest.fn(); +jest.mock('./directLine/mountDirectLineRoutes', () => ({ + mountDirectLineRoutes: server => mockMountDirectLineRoutes(server), +})); +const mockMountEmulatorRoutes = jest.fn(); +jest.mock('./emulator/mountEmulatorRoutes', () => ({ + mountEmulatorRoutes: server => mockMountEmulatorRoutes(server), +})); +const mockMountSessionRoutes = jest.fn(); +jest.mock('./channel/session/mountSessionRoutes', () => ({ + mountSessionRoutes: server => mockMountSessionRoutes(server), +})); +const mockMountUserTokenRoutes = jest.fn(); +jest.mock('./channel/userToken/mountUserTokenRoutes', () => ({ + mountUserTokenRoutes: server => mockMountUserTokenRoutes(server), +})); + +describe('mountAllRoutes', () => { + it('should mount all routes', () => { + const emulatorServer: any = {}; + mountAllRoutes(emulatorServer); + + expect(mockMountAttachmentsRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountBotStateRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountConversationsRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountDirectLineRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountEmulatorRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountSessionRoutes).toHaveBeenCalledWith(emulatorServer); + expect(mockMountUserTokenRoutes).toHaveBeenCalledWith(emulatorServer); + }); +}); diff --git a/packages/emulator/core/src/attachments/registerRoutes.ts b/packages/app/main/src/server/routes/mountAllRoutes.ts similarity index 59% rename from packages/emulator/core/src/attachments/registerRoutes.ts rename to packages/app/main/src/server/routes/mountAllRoutes.ts index 4f170119d..1ae6568d2 100644 --- a/packages/emulator/core/src/attachments/registerRoutes.ts +++ b/packages/app/main/src/server/routes/mountAllRoutes.ts @@ -31,31 +31,22 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { RequestHandlerType, Server } from 'restify'; +import { EmulatorRestServer } from '../restServer'; -import { BotEmulator } from '../botEmulator'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; +import { mountAttachmentsRoutes } from './channel/attachments/mountAttachmentsRoutes'; +import { mountBotStateRoutes } from './channel/botState/mountBotStateRoutes'; +import { mountConversationsRoutes } from './channel/conversations/mountConversationsRoutes'; +import { mountDirectLineRoutes } from './directLine/mountDirectLineRoutes'; +import { mountEmulatorRoutes } from './emulator/mountEmulatorRoutes'; +import { mountSessionRoutes } from './channel/session/mountSessionRoutes'; +import { mountUserTokenRoutes } from './channel/userToken/mountUserTokenRoutes'; -import getAttachment from './middleware/getAttachment'; -import getAttachmentInfo from './middleware/getAttachmentInfo'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandlerType[]) { - const facility = getFacility('attachments'); - - server.get( - '/v3/attachments/:attachmentId', - ...uses, - facility, - getRouteName('getAttachmentInfo'), - getAttachmentInfo(botEmulator) - ); - - server.get( - '/v3/attachments/:attachmentId/views/:viewId', - ...uses, - facility, - getRouteName('getAttachment'), - getAttachment(botEmulator) - ); +export function mountAllRoutes(emulatorServer: EmulatorRestServer): void { + mountAttachmentsRoutes(emulatorServer); + mountBotStateRoutes(emulatorServer); + mountConversationsRoutes(emulatorServer); + mountDirectLineRoutes(emulatorServer); + mountEmulatorRoutes(emulatorServer); + mountSessionRoutes(emulatorServer); + mountUserTokenRoutes(emulatorServer); } diff --git a/packages/emulator/core/src/facility/attachments.spec.ts b/packages/app/main/src/server/state/attachments.spec.ts similarity index 90% rename from packages/emulator/core/src/facility/attachments.spec.ts rename to packages/app/main/src/server/state/attachments.spec.ts index d90f44144..386f68f0c 100644 --- a/packages/emulator/core/src/facility/attachments.spec.ts +++ b/packages/app/main/src/server/state/attachments.spec.ts @@ -31,10 +31,14 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import Attachments from './attachments'; +import { Attachments } from './attachments'; -jest.mock('../utils/uniqueId', () => jest.fn(() => '1234')); -jest.mock('../utils/createResponse/apiException', () => jest.fn(() => 'I am an error!')); +jest.mock('../utils/uniqueId', () => ({ + uniqueId: jest.fn(() => '1234'), +})); +jest.mock('../utils/createResponse/createAPIException', () => ({ + createAPIException: jest.fn(() => 'I am an error!'), +})); describe('Attachments', () => { const attachments = new Attachments(); diff --git a/packages/emulator/core/src/facility/attachments.ts b/packages/app/main/src/server/state/attachments.ts similarity index 93% rename from packages/emulator/core/src/facility/attachments.ts rename to packages/app/main/src/server/state/attachments.ts index a97c71176..8688d8744 100644 --- a/packages/emulator/core/src/facility/attachments.ts +++ b/packages/app/main/src/server/state/attachments.ts @@ -35,10 +35,10 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import { AttachmentData } from 'botframework-schema'; import * as HttpStatus from 'http-status-codes'; -import createAPIException from '../utils/createResponse/apiException'; -import uniqueId from '../utils/uniqueId'; +import { createAPIException } from '../utils/createResponse/createAPIException'; +import { uniqueId } from '../utils/uniqueId'; -export default class Attachments { +export class Attachments { private attachments: { [key: string]: AttachmentData } = {}; public getAttachmentData(id: string): AttachmentData { diff --git a/packages/emulator/core/src/facility/botDataKey.spec.ts b/packages/app/main/src/server/state/botDataKey.spec.ts similarity index 97% rename from packages/emulator/core/src/facility/botDataKey.spec.ts rename to packages/app/main/src/server/state/botDataKey.spec.ts index 35eda5b35..12886fb40 100644 --- a/packages/emulator/core/src/facility/botDataKey.spec.ts +++ b/packages/app/main/src/server/state/botDataKey.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import botDataKey from './botDataKey'; +import { botDataKey } from './botDataKey'; describe('botDataKey', () => { it('should return a bot data key', () => { diff --git a/packages/emulator/core/src/facility/botDataKey.ts b/packages/app/main/src/server/state/botDataKey.ts similarity index 93% rename from packages/emulator/core/src/facility/botDataKey.ts rename to packages/app/main/src/server/state/botDataKey.ts index fbddd4d5a..b006d6183 100644 --- a/packages/emulator/core/src/facility/botDataKey.ts +++ b/packages/app/main/src/server/state/botDataKey.ts @@ -31,6 +31,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -export default function botDataKey(channelId: string, conversationId: string, userId: string) { +export function botDataKey(channelId: string, conversationId: string, userId: string) { return `${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`; } diff --git a/packages/emulator/core/src/facility/botEndpoint.spec.ts b/packages/app/main/src/server/state/botEndpoint.spec.ts similarity index 99% rename from packages/emulator/core/src/facility/botEndpoint.spec.ts rename to packages/app/main/src/server/state/botEndpoint.spec.ts index 95a468580..408f92e3e 100644 --- a/packages/emulator/core/src/facility/botEndpoint.spec.ts +++ b/packages/app/main/src/server/state/botEndpoint.spec.ts @@ -33,9 +33,9 @@ import { URLSearchParams } from 'url'; -import { authentication, usGovernmentAuthentication } from '../authEndpoints'; +import { authentication, usGovernmentAuthentication } from '../constants/authEndpoints'; -import BotEndpoint from './botEndpoint'; +import { BotEndpoint } from './botEndpoint'; describe('BotEndpoint', () => { it('should determine whether a token will expire within a time period', () => { diff --git a/packages/emulator/core/src/facility/botEndpoint.ts b/packages/app/main/src/server/state/botEndpoint.ts similarity index 97% rename from packages/emulator/core/src/facility/botEndpoint.ts rename to packages/app/main/src/server/state/botEndpoint.ts index 66d7cd1d4..83c17af81 100644 --- a/packages/emulator/core/src/facility/botEndpoint.ts +++ b/packages/app/main/src/server/state/botEndpoint.ts @@ -36,13 +36,13 @@ import { URL, URLSearchParams } from 'url'; import { BotEndpointOptions, SpeechAuthenticationToken } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import { authentication, speech as speechEndpoint, usGovernmentAuthentication } from '../authEndpoints'; -import statusCodeFamily from '../utils/statusCodeFamily'; +import { authentication, speech as speechEndpoint, usGovernmentAuthentication } from '../constants/authEndpoints'; +import { statusCodeFamily } from '../utils/statusCodeFamily'; // We will refresh if the token is going to expire within 5 minutes const TIME_TO_REFRESH = 5 * 60 * 1000; -export default class BotEndpoint { +export class BotEndpoint { public accessToken?: string; public accessTokenExpires?: number; public appId?: string; @@ -135,7 +135,8 @@ export default class BotEndpoint { if ( (response.status === HttpStatus.UNAUTHORIZED || response.status === HttpStatus.FORBIDDEN) && - (!forceRefresh && this.msaAppId) + !forceRefresh && + this.msaAppId ) { return this.fetchWithAuth(url, fetchOptions, true); } diff --git a/packages/emulator/core/src/facility/consoleLogService.spec.ts b/packages/app/main/src/server/state/consoleLogService.spec.ts similarity index 98% rename from packages/emulator/core/src/facility/consoleLogService.spec.ts rename to packages/app/main/src/server/state/consoleLogService.spec.ts index 1ab90f3d7..ea0141f13 100644 --- a/packages/emulator/core/src/facility/consoleLogService.spec.ts +++ b/packages/app/main/src/server/state/consoleLogService.spec.ts @@ -34,7 +34,7 @@ import { LogLevel } from '@bfemulator/sdk-shared'; import log from 'npmlog'; -import ConsoleLogService from './consoleLogService'; +import { ConsoleLogService } from './consoleLogService'; jest.mock('npmlog', () => ({ error: jest.fn(() => null), diff --git a/packages/emulator/core/src/facility/consoleLogService.ts b/packages/app/main/src/server/state/consoleLogService.ts similarity index 97% rename from packages/emulator/core/src/facility/consoleLogService.ts rename to packages/app/main/src/server/state/consoleLogService.ts index cd5e3e06c..c5d641d29 100644 --- a/packages/emulator/core/src/facility/consoleLogService.ts +++ b/packages/app/main/src/server/state/consoleLogService.ts @@ -50,7 +50,7 @@ function logLevel(logLevelArg: LogLevel) { } } -export default class ConsoleLogService implements LogService { +export class ConsoleLogService implements LogService { public logToChat(conversationId: string, ...items: LogItem[]) { items.forEach(message => { if (message.type === LogItemType.Text) { diff --git a/packages/emulator/core/src/facility/conversation.spec.ts b/packages/app/main/src/server/state/conversation.spec.ts similarity index 93% rename from packages/emulator/core/src/facility/conversation.spec.ts rename to packages/app/main/src/server/state/conversation.spec.ts index 14344ee34..872814ca1 100644 --- a/packages/emulator/core/src/facility/conversation.spec.ts +++ b/packages/app/main/src/server/state/conversation.spec.ts @@ -31,10 +31,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { BotEmulator } from '../botEmulator'; - -import BotEndpoint from './botEndpoint'; -import Conversation from './conversation'; +import { BotEndpoint } from './botEndpoint'; +import { Conversation } from './conversation'; const mockTranscript = [ { @@ -166,7 +164,6 @@ const mockUserActivity = { describe('Conversation class', () => { let botEndpointBotId; let botEndpoint; - let botEmulator: any; let conversation: Conversation; let conversationId; let user: any; @@ -185,16 +182,24 @@ describe('Conversation class', () => { beforeEach(() => { botEndpointBotId = 'someBotEndpointBotId'; botEndpoint = new BotEndpoint('123', botEndpointBotId, 'http://ngrok', null, null, null, null, { fetch }); - botEmulator = new BotEmulator(async () => 'http://localhost', { - fetch, - loggerOrLogService: { - logMessage: async () => true, - logActivity: async () => true, - } as any, - }); + const mockEmulatorServer: any = { + getServiceUrl: jest.fn().mockResolvedValue('http://localhost'), + logger: { + logActivity: jest.fn(), + logException: jest.fn(), + logMessage: jest.fn(), + }, + state: { + currentUserId: 'someUserId', + locale: 'en-us', + users: { + usersById: jest.fn(() => {}), + }, + }, + }; conversationId = 'someConversationId'; user = { id: 'someUserId' }; - conversation = new Conversation(botEmulator, botEndpoint, conversationId, user); + conversation = new Conversation(mockEmulatorServer, botEndpoint, conversationId, user, 'livechat'); }); it('should feed activities', () => { @@ -304,7 +309,10 @@ describe('Conversation class', () => { name: 'Bot', }, ], - membersRemoved: [{ id: '5e1f1c4c-6a89-4880-8db0-0f222c07ae9a', name: 'User' }, { id: '1', name: 'Bot' }], + membersRemoved: [ + { id: '5e1f1c4c-6a89-4880-8db0-0f222c07ae9a', name: 'User' }, + { id: '1', name: 'Bot' }, + ], type: 'conversationUpdate', }, false diff --git a/packages/emulator/core/src/facility/conversation.ts b/packages/app/main/src/server/state/conversation.ts similarity index 90% rename from packages/emulator/core/src/facility/conversation.ts rename to packages/app/main/src/server/state/conversation.ts index adcd48291..e4368adae 100644 --- a/packages/emulator/core/src/facility/conversation.ts +++ b/packages/app/main/src/server/state/conversation.ts @@ -65,15 +65,15 @@ import { } from 'botframework-schema'; import { traceContainsDebugData, ValueTypesMask } from '@bfemulator/app-shared'; -import { BotEmulator } from '../botEmulator'; -import { TokenCache } from '../userToken/tokenCache'; -import createAPIException from '../utils/createResponse/apiException'; -import createResourceResponse from '../utils/createResponse/resource'; -import OAuthClientEncoder from '../utils/oauthClientEncoder'; -import PaymentEncoder from '../utils/paymentEncoder'; -import uniqueId from '../utils/uniqueId'; +import { TokenCache } from '../routes/channel/userToken/tokenCache'; +import { createAPIException } from '../utils/createResponse/createAPIException'; +import { createResourceResponse } from '../utils/createResponse/createResourceResponse'; +import { OAuthClientEncoder } from '../utils/oauthClientEncoder'; +import { PaymentEncoder } from '../utils/paymentEncoder'; +import { uniqueId } from '../utils/uniqueId'; +import { EmulatorRestServer } from '../restServer'; -import BotEndpoint from './botEndpoint'; +import { BotEndpoint } from './botEndpoint'; // moment currently does not export callable function // eslint-disable-next-line typescript/no-var-requires @@ -88,10 +88,10 @@ interface ActivityBucket { /** * Stores and propagates conversation messages. */ -export default class Conversation extends EventEmitter { - public botEmulator: BotEmulator; +export class Conversation extends EventEmitter { public botEndpoint: BotEndpoint; public conversationId: string; + public emulatorServer: EmulatorRestServer; public user: User; public mode: EmulatorMode; // flag indicating if the user has been shown the @@ -110,14 +110,14 @@ export default class Conversation extends EventEmitter { } constructor( - botEmulator: BotEmulator, + emulatorServer: EmulatorRestServer, botEndpoint: BotEndpoint, conversationId: string, user: User, mode: EmulatorMode ) { super(); - Object.assign(this, { botEmulator, botEndpoint, conversationId, user, mode }); + Object.assign(this, { emulatorServer, botEndpoint, conversationId, user, mode }); // We should consider hardcoding bot id because we don't really use it this.members.push({ id: (botEndpoint && botEndpoint.botId) || 'bot-1', @@ -136,7 +136,7 @@ export default class Conversation extends EventEmitter { */ public async postActivityToBot(activity: Activity, recordInConversation: boolean) { if (!this.botEndpoint) { - return this.botEmulator.facilities.logger.logMessage( + return this.emulatorServer.logger.logMessage( this.conversationId, textItem( LogLevel.Error, @@ -148,7 +148,7 @@ export default class Conversation extends EventEmitter { // Do not make a shallow copy here before modifying activity = this.postage(this.botEndpoint.botId, activity); activity.from = activity.from || this.user; - activity.locale = this.botEmulator.facilities.locale; + activity.locale = this.emulatorServer.state.locale; if (!activity.recipient.name) { activity.recipient.name = 'Bot'; @@ -159,14 +159,14 @@ export default class Conversation extends EventEmitter { activity.recipient.role = 'bot'; } - activity.serviceUrl = await this.botEmulator.getServiceUrl(this.botEndpoint.botUrl); + activity.serviceUrl = await this.emulatorServer.getServiceUrl(this.botEndpoint.botUrl); if ( !this.conversationIsTranscript && !isLocalHostUrl(this.botEndpoint.botUrl) && isLocalHostUrl(activity.serviceUrl) ) { - this.botEmulator.facilities.logger.logMessage( + this.emulatorServer.logger.logMessage( this.conversationId, textItem( LogLevel.Error, @@ -174,11 +174,11 @@ export default class Conversation extends EventEmitter { ' Without tunneling software you will not receive replies.' ) ); - this.botEmulator.facilities.logger.logMessage( + this.emulatorServer.logger.logMessage( this.conversationId, externalLinkItem('Connecting to bots hosted remotely', 'https://aka.ms/cnjvpo') ); - this.botEmulator.facilities.logger.logMessage(this.conversationId, appSettingsItem('Configure ngrok')); + this.emulatorServer.logger.logMessage(this.conversationId, appSettingsItem('Configure ngrok')); } const options = { @@ -230,11 +230,11 @@ export default class Conversation extends EventEmitter { const result = await this.postActivityToBot(activity as Activity, false); if (!/2\d\d/.test('' + result.statusCode)) { - this.botEmulator.facilities.logger.logException(this.conversationId, result.response); + this.emulatorServer.logger.logException(this.conversationId, result.response); } const { headers, message } = result.response; - this.botEmulator.facilities.logger.logMessage( + this.emulatorServer.logger.logMessage( this.conversationId, networkRequestItem( 'directline', @@ -274,7 +274,7 @@ export default class Conversation extends EventEmitter { } if (!activity.locale) { - activity.locale = this.botEmulator.facilities.locale; + activity.locale = this.emulatorServer.state.locale; } // Fill in role field, if missing @@ -306,7 +306,7 @@ export default class Conversation extends EventEmitter { // This function turns local contentUrls into dataUrls:// public async processActivityForDataUrls(activity: Activity): Promise { - const visitor = new DataUrlEncoder(this.botEmulator); + const visitor = new DataUrlEncoder(this.emulatorServer); activity = { ...activity }; await visitor.traverseActivity(activity); @@ -420,7 +420,7 @@ export default class Conversation extends EventEmitter { try { await this.postActivityToBot(activity as Activity, false); } catch (err) { - this.botEmulator.facilities.logger.logException(this.conversationId, err); + this.emulatorServer.logger.logException(this.conversationId, err); } this.transcript = [...this.transcript, { type: 'contact update', activity } as TranscriptRecord]; @@ -436,7 +436,7 @@ export default class Conversation extends EventEmitter { try { await this.postActivityToBot(activity as Activity, false); } catch (err) { - this.botEmulator.facilities.logger.logException(this.conversationId, err); + this.emulatorServer.logger.logException(this.conversationId, err); } this.transcript = [...this.transcript, { type: 'contact remove', activity } as TranscriptRecord]; @@ -452,7 +452,7 @@ export default class Conversation extends EventEmitter { try { await this.postActivityToBot(activity, false); } catch (err) { - this.botEmulator.facilities.logger.logException(this.conversationId, err); + this.emulatorServer.logger.logException(this.conversationId, err); } this.transcript = [...this.transcript, { type: 'typing', activity }]; @@ -468,7 +468,7 @@ export default class Conversation extends EventEmitter { try { await this.postActivityToBot(activity, false); } catch (err) { - this.botEmulator.facilities.logger.logException(this.conversationId, err); + this.emulatorServer.logger.logException(this.conversationId, err); } this.transcript = [...this.transcript, { type: 'ping', activity }]; @@ -483,7 +483,7 @@ export default class Conversation extends EventEmitter { try { await this.postActivityToBot(activity, false); } catch (err) { - this.botEmulator.facilities.logger.logException(this.conversationId, err); + this.emulatorServer.logger.logException(this.conversationId, err); } this.transcript = [...this.transcript, { type: 'user data delete', activity }]; @@ -529,7 +529,7 @@ export default class Conversation extends EventEmitter { payerPhone: string ) { if (!this.botEndpoint) { - return this.botEmulator.facilities.logger.logMessage( + return this.emulatorServer.logger.logMessage( this.conversationId, textItem( LogLevel.Error, @@ -580,8 +580,8 @@ export default class Conversation extends EventEmitter { bot: { id: this.botEndpoint.botId } as ChannelAccount, channelId: 'emulator', conversation: { id: this.conversationId } as ConversationAccount, - serviceUrl: await this.botEmulator.getServiceUrl(this.botEndpoint.botUrl), - user: this.botEmulator.facilities.users.usersById(this.botEmulator.facilities.users.currentUserId), + serviceUrl: await this.emulatorServer.getServiceUrl(this.botEndpoint.botUrl), + user: this.emulatorServer.state.users.usersById(this.emulatorServer.state.users.currentUserId), }, value: updateValue, } as IInvokeActivity; @@ -592,7 +592,7 @@ export default class Conversation extends EventEmitter { } public async sendTokenResponse(connectionName: string, token: string, doNotCache?: boolean) { - const userId = this.botEmulator.facilities.users.currentUserId; + const userId = this.emulatorServer.state.users.currentUserId; if (!doNotCache) { TokenCache.addTokenToCache(this.botEndpoint.botId, userId, connectionName, token); @@ -720,7 +720,7 @@ export default class Conversation extends EventEmitter { shippingOptionId: string ) { if (!this.botEndpoint) { - return this.botEmulator.facilities.logger.logMessage( + return this.emulatorServer.logger.logMessage( this.conversationId, textItem( LogLevel.Error, @@ -746,8 +746,8 @@ export default class Conversation extends EventEmitter { bot: { id: this.botEndpoint.botId }, channelId: 'emulator', conversation: { id: this.conversationId }, - serviceUrl: await this.botEmulator.getServiceUrl(this.botEndpoint.botUrl), - user: this.botEmulator.facilities.users.usersById(this.botEmulator.facilities.users.currentUserId), + serviceUrl: await this.emulatorServer.getServiceUrl(this.botEndpoint.botUrl), + user: this.emulatorServer.state.users.usersById(this.emulatorServer.state.users.currentUserId), }, value: updateValue, } as IInvokeActivity; @@ -786,13 +786,13 @@ export default class Conversation extends EventEmitter { } if (activity && activity.recipient) { - this.botEmulator.facilities.logger.logActivity(this.conversationId, activity, activity.recipient.role); + this.emulatorServer.logger.logActivity(this.conversationId, activity, activity.recipient.role); } } } class DataUrlEncoder { - constructor(public bot: BotEmulator) { + constructor(public bot: EmulatorRestServer) { // the constructor only exists so we can pass in the bot } diff --git a/packages/emulator/core/src/facility/conversationSet.spec.ts b/packages/app/main/src/server/state/conversationSet.spec.ts similarity index 98% rename from packages/emulator/core/src/facility/conversationSet.spec.ts rename to packages/app/main/src/server/state/conversationSet.spec.ts index 9483b57f6..764489ee9 100644 --- a/packages/emulator/core/src/facility/conversationSet.spec.ts +++ b/packages/app/main/src/server/state/conversationSet.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import ConversationSet from './conversationSet'; +import { ConversationSet } from './conversationSet'; describe('The conversationSet', () => { let conversationSet: ConversationSet; diff --git a/packages/emulator/core/src/facility/conversationSet.ts b/packages/app/main/src/server/state/conversationSet.ts similarity index 88% rename from packages/emulator/core/src/facility/conversationSet.ts rename to packages/app/main/src/server/state/conversationSet.ts index 9827f180a..7408f6a81 100644 --- a/packages/emulator/core/src/facility/conversationSet.ts +++ b/packages/app/main/src/server/state/conversationSet.ts @@ -36,26 +36,26 @@ import { EventEmitter } from 'events'; import { User } from '@bfemulator/sdk-shared'; import { EmulatorMode } from '@bfemulator/sdk-shared'; -import { BotEmulator } from '../botEmulator'; -import uniqueId from '../utils/uniqueId'; +import { uniqueId } from '../utils/uniqueId'; +import { EmulatorRestServer } from '../restServer'; -import BotEndpoint from './botEndpoint'; -import Conversation from './conversation'; +import { BotEndpoint } from './botEndpoint'; +import { Conversation } from './conversation'; /** * A set of conversations with a bot. */ -export default class ConversationSet extends EventEmitter { +export class ConversationSet extends EventEmitter { public conversations: { [conversationId: string]: Conversation } = {}; // TODO: May be we want to move "bot" back to the constructor public newConversation( - botEmulator: BotEmulator, + emulatorServer: EmulatorRestServer, botEndpoint: BotEndpoint, user: User, conversationId = uniqueId(), mode: EmulatorMode = 'livechat' ): Conversation { - const conversation = new Conversation(botEmulator, botEndpoint, conversationId, user, mode); + const conversation = new Conversation(emulatorServer, botEndpoint, conversationId, user, mode); // This should always result in a livechat being opened // unless there is already a livechat or transcript queued // we add the "|livechat" string to the end of the conversationId diff --git a/packages/emulator/core/src/facility/endpointSet.spec.ts b/packages/app/main/src/server/state/endpointSet.spec.ts similarity index 92% rename from packages/emulator/core/src/facility/endpointSet.spec.ts rename to packages/app/main/src/server/state/endpointSet.spec.ts index e675f6a87..f7538331d 100644 --- a/packages/emulator/core/src/facility/endpointSet.spec.ts +++ b/packages/app/main/src/server/state/endpointSet.spec.ts @@ -31,23 +31,22 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import Endpoints from './endpointSet'; -import BotEndpoint from './botEndpoint'; +import { EndpointSet } from './endpointSet'; +import { BotEndpoint } from './botEndpoint'; const mockId = '1234'; -jest.mock('../utils/uniqueId', () => jest.fn(() => mockId)); +jest.mock('../utils/uniqueId', () => ({ + uniqueId: jest.fn(() => mockId), +})); let mockDecodedToken; jest.mock('on-error-resume-next', () => jest.fn(() => mockDecodedToken)); describe('Endpoints', () => { - let endpoints: Endpoints; + let endpoints: EndpointSet; const mockFetch = jest.fn(() => null); beforeEach(() => { - const options: any = { - fetch: mockFetch, - }; - endpoints = new Endpoints(options); + endpoints = new EndpointSet(mockFetch); mockDecodedToken = { endpointId: 'someOtherId' }; }); @@ -62,7 +61,7 @@ describe('Endpoints', () => { channelService: undefined, }; // with an id - let pushedEndpoint = endpoints.push(id, botEndpoint); + let pushedEndpoint = endpoints.set(id, botEndpoint); expect(pushedEndpoint).toEqual( new BotEndpoint( @@ -81,7 +80,7 @@ describe('Endpoints', () => { expect((endpoints as any)._endpoints[id]).toEqual(pushedEndpoint); // with no id - pushedEndpoint = endpoints.push('', botEndpoint); + pushedEndpoint = endpoints.set('', botEndpoint); expect(pushedEndpoint).toEqual( new BotEndpoint( @@ -101,7 +100,7 @@ describe('Endpoints', () => { // with no id or url botEndpoint.botUrl = ''; - pushedEndpoint = endpoints.push('', botEndpoint); + pushedEndpoint = endpoints.set('', botEndpoint); expect(pushedEndpoint).toEqual( new BotEndpoint( @@ -125,7 +124,7 @@ describe('Endpoints', () => { (endpoints as any)._endpoints['someId'] = endpoint; expect((endpoints as any)._endpoints['someId']).toBe(endpoint); - endpoints.reset(); + endpoints.clear(); expect((endpoints as any)._endpoints['someId']).toBe(undefined); }); diff --git a/packages/emulator/core/src/facility/endpointSet.ts b/packages/app/main/src/server/state/endpointSet.ts similarity index 88% rename from packages/emulator/core/src/facility/endpointSet.ts rename to packages/app/main/src/server/state/endpointSet.ts index 561e654eb..3b8532adf 100644 --- a/packages/emulator/core/src/facility/endpointSet.ts +++ b/packages/app/main/src/server/state/endpointSet.ts @@ -31,21 +31,20 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import { BotEmulatorOptions } from '@bfemulator/sdk-shared'; import base64Url from 'base64url'; import onErrorResumeNext from 'on-error-resume-next'; -import uniqueId from '../utils/uniqueId'; +import { uniqueId } from '../utils/uniqueId'; -import BotEndpoint from './botEndpoint'; +import { BotEndpoint } from './botEndpoint'; const { decode } = base64Url; -export default class Endpoints { +export class EndpointSet { private _endpoints: { [key: string]: BotEndpoint } = {}; - constructor(private _options: BotEmulatorOptions) {} + constructor(private _fetch: (url: string, options?: any) => Promise) {} - public push(id: string, botEndpoint: Partial): BotEndpoint { + public set(id: string, botEndpoint: Partial): BotEndpoint { id = id || botEndpoint.botUrl || uniqueId(); const botEndpointInstance = new BotEndpoint( @@ -57,7 +56,7 @@ export default class Endpoints { botEndpoint.use10Tokens, botEndpoint.channelService, { - fetch: this._options.fetch, + fetch: this._fetch, } ); @@ -66,7 +65,7 @@ export default class Endpoints { return botEndpointInstance; } - public reset() { + public clear() { this._endpoints = {}; } diff --git a/packages/emulator/core/src/facility/loggerAdapter.spec.ts b/packages/app/main/src/server/state/loggerAdapter.spec.ts similarity index 98% rename from packages/emulator/core/src/facility/loggerAdapter.spec.ts rename to packages/app/main/src/server/state/loggerAdapter.spec.ts index 1239df8a6..bae1bd2e2 100644 --- a/packages/emulator/core/src/facility/loggerAdapter.spec.ts +++ b/packages/app/main/src/server/state/loggerAdapter.spec.ts @@ -35,7 +35,7 @@ import { exceptionItem, inspectableObjectItem, LogLevel, summaryTextItem, textIt import { Activity, ActivityTypes } from 'botframework-schema'; import { LogItem } from '@bfemulator/sdk-shared/build/src'; -import LoggerAdapter from './loggerAdapter'; +import { LoggerAdapter } from './loggerAdapter'; describe('LoggerAdapter', () => { const mockLogToChat = jest.fn(() => null); diff --git a/packages/emulator/core/src/facility/loggerAdapter.ts b/packages/app/main/src/server/state/loggerAdapter.ts similarity index 98% rename from packages/emulator/core/src/facility/loggerAdapter.ts rename to packages/app/main/src/server/state/loggerAdapter.ts index b3f0914aa..299f56a80 100644 --- a/packages/emulator/core/src/facility/loggerAdapter.ts +++ b/packages/app/main/src/server/state/loggerAdapter.ts @@ -42,7 +42,7 @@ import { } from '@bfemulator/sdk-shared'; import { Activity, ActivityTypes } from 'botframework-schema'; -export default class LoggerAdapter implements Logger { +export class LoggerAdapter implements Logger { private static getDirectionalArrowFromRole(role: string): string { if (role === 'user') { return '<- '; diff --git a/packages/app/main/src/server/state/serverState.ts b/packages/app/main/src/server/state/serverState.ts new file mode 100644 index 000000000..3df1eadda --- /dev/null +++ b/packages/app/main/src/server/state/serverState.ts @@ -0,0 +1,49 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// +// Microsoft Bot Framework: http://botframework.com +// +// Bot Framework Emulator Github: +// https://github.com/Microsoft/BotFramwork-Emulator +// +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License: +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import { Attachments } from './attachments'; +import { ConversationSet } from './conversationSet'; +import { EndpointSet } from './endpointSet'; +import { Users } from './users'; + +export class ServerState { + public attachments = new Attachments(); + public conversations = new ConversationSet(); + public endpoints: EndpointSet; + public users = new Users(); + public locale?: string; + + constructor(fetch: (url: string, options?: any) => Promise) { + this.endpoints = new EndpointSet(fetch); + } +} diff --git a/packages/emulator/core/src/facility/users.spec.ts b/packages/app/main/src/server/state/users.spec.ts similarity index 98% rename from packages/emulator/core/src/facility/users.spec.ts rename to packages/app/main/src/server/state/users.spec.ts index 1415014b9..326095395 100644 --- a/packages/emulator/core/src/facility/users.spec.ts +++ b/packages/app/main/src/server/state/users.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import Users from './users'; +import { Users } from './users'; describe('Users', () => { it('should initialize with a default current user id', () => { diff --git a/packages/emulator/core/src/facility/users.ts b/packages/app/main/src/server/state/users.ts similarity index 98% rename from packages/emulator/core/src/facility/users.ts rename to packages/app/main/src/server/state/users.ts index a4fa9f256..b0a647360 100644 --- a/packages/emulator/core/src/facility/users.ts +++ b/packages/app/main/src/server/state/users.ts @@ -33,7 +33,7 @@ import { User } from '@bfemulator/sdk-shared'; -export default class Users { +export class Users { public currentUserId: string = 'default-user'; public users: { [userId: string]: User }; diff --git a/packages/emulator/core/src/utils/activityVisitor.spec.ts b/packages/app/main/src/server/utils/activityVisitor.spec.ts similarity index 99% rename from packages/emulator/core/src/utils/activityVisitor.spec.ts rename to packages/app/main/src/server/utils/activityVisitor.spec.ts index 10b5958f3..8036f2937 100644 --- a/packages/emulator/core/src/utils/activityVisitor.spec.ts +++ b/packages/app/main/src/server/utils/activityVisitor.spec.ts @@ -41,7 +41,8 @@ import { ThumbnailCard, } from '@bfemulator/sdk-shared'; -import ActivityVisitor from './activityVisitor'; +import { ActivityVisitor } from './activityVisitor'; + class MockActivityVisitor extends ActivityVisitor { public cardActionVisitors: CardAction[] = []; diff --git a/packages/emulator/core/src/utils/activityVisitor.ts b/packages/app/main/src/server/utils/activityVisitor.ts similarity index 98% rename from packages/emulator/core/src/utils/activityVisitor.ts rename to packages/app/main/src/server/utils/activityVisitor.ts index 03665bd60..cf355c220 100644 --- a/packages/emulator/core/src/utils/activityVisitor.ts +++ b/packages/app/main/src/server/utils/activityVisitor.ts @@ -44,7 +44,7 @@ import { } from 'botframework-schema'; import { AttachmentContentTypes } from '@bfemulator/sdk-shared'; -export default abstract class ActivityVisitor { +export abstract class ActivityVisitor { public traverseActivity(messageActivity: Activity) { if (!messageActivity) { return; diff --git a/packages/emulator/core/src/utils/approximateObjectSize.spec.ts b/packages/app/main/src/server/utils/approximateObjectSize.spec.ts similarity index 96% rename from packages/emulator/core/src/utils/approximateObjectSize.spec.ts rename to packages/app/main/src/server/utils/approximateObjectSize.spec.ts index f19558448..c5dc884f8 100644 --- a/packages/emulator/core/src/utils/approximateObjectSize.spec.ts +++ b/packages/app/main/src/server/utils/approximateObjectSize.spec.ts @@ -30,7 +30,8 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import approximateObjectSize from './approximateObjectSize'; + +import { approximateObjectSize } from './approximateObjectSize'; describe('The approximateObjectSize util', () => { it('should calculate the approximate size of an object', () => { diff --git a/packages/emulator/core/src/utils/approximateObjectSize.ts b/packages/app/main/src/server/utils/approximateObjectSize.ts similarity index 96% rename from packages/emulator/core/src/utils/approximateObjectSize.ts rename to packages/app/main/src/server/utils/approximateObjectSize.ts index 69556a9bd..7d208e0fc 100644 --- a/packages/emulator/core/src/utils/approximateObjectSize.ts +++ b/packages/app/main/src/server/utils/approximateObjectSize.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -export default function approximateObjectSize(object: any, cache: any[] = []): number { +export function approximateObjectSize(object: any, cache: any[] = []): number { switch (typeof object) { case 'boolean': return 4; diff --git a/packages/emulator/core/src/utils/createResponse/apiException.spec.ts b/packages/app/main/src/server/utils/createResponse/createAPIException.spec.ts similarity index 91% rename from packages/emulator/core/src/utils/createResponse/apiException.spec.ts rename to packages/app/main/src/server/utils/createResponse/createAPIException.spec.ts index f1c15e44e..4d7c8e439 100644 --- a/packages/emulator/core/src/utils/createResponse/apiException.spec.ts +++ b/packages/app/main/src/server/utils/createResponse/createAPIException.spec.ts @@ -31,11 +31,11 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import createApiException from './apiException'; +import { createAPIException } from './createAPIException'; -describe('createApiException', () => { +describe('createAPIException', () => { it('should create an api exception', () => { - const exception = createApiException(500, '500', 'Internal server error.'); + const exception = createAPIException(500, '500', 'Internal server error.'); expect(exception.statusCode).toBe(500); expect(exception.error).toEqual({ diff --git a/packages/emulator/core/src/utils/createResponse/apiException.ts b/packages/app/main/src/server/utils/createResponse/createAPIException.ts similarity index 94% rename from packages/emulator/core/src/utils/createResponse/apiException.ts rename to packages/app/main/src/server/utils/createResponse/createAPIException.ts index b6a092abe..89e788f20 100644 --- a/packages/emulator/core/src/utils/createResponse/apiException.ts +++ b/packages/app/main/src/server/utils/createResponse/createAPIException.ts @@ -44,7 +44,7 @@ function createErrorResponse(code: string, message: string): ErrorResponse { } // Create Exception -export default function createAPIException(statusCode: number, code: string, message: string): APIException { +export function createAPIException(statusCode: number, code: string, message: string): APIException { return { statusCode, error: createErrorResponse(code, message), diff --git a/packages/emulator/core/src/utils/createResponse/conversation.spec.ts b/packages/app/main/src/server/utils/createResponse/createConversationResponse.spec.ts similarity index 95% rename from packages/emulator/core/src/utils/createResponse/conversation.spec.ts rename to packages/app/main/src/server/utils/createResponse/createConversationResponse.spec.ts index ba4d222bc..55b54aab5 100644 --- a/packages/emulator/core/src/utils/createResponse/conversation.spec.ts +++ b/packages/app/main/src/server/utils/createResponse/createConversationResponse.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import createConversationResponse from './conversation'; +import { createConversationResponse } from './createConversationResponse'; describe('createConversationResponse', () => { it('should create a conversation response', () => { diff --git a/packages/emulator/core/src/utils/createResponse/conversation.ts b/packages/app/main/src/server/utils/createResponse/createConversationResponse.ts similarity index 92% rename from packages/emulator/core/src/utils/createResponse/conversation.ts rename to packages/app/main/src/server/utils/createResponse/createConversationResponse.ts index ff7b60733..cb080f139 100644 --- a/packages/emulator/core/src/utils/createResponse/conversation.ts +++ b/packages/app/main/src/server/utils/createResponse/createConversationResponse.ts @@ -33,10 +33,7 @@ import { ConversationResourceResponse } from '@bfemulator/sdk-shared'; -export default function createConversationResponse( - id: string, - activityId: string | null -): ConversationResourceResponse { +export function createConversationResponse(id: string, activityId: string | null): ConversationResourceResponse { const response: ConversationResourceResponse = { id }; if (activityId !== null) { diff --git a/packages/emulator/core/src/utils/createResponse/error.spec.ts b/packages/app/main/src/server/utils/createResponse/createErrorResponse.spec.ts similarity index 96% rename from packages/emulator/core/src/utils/createResponse/error.spec.ts rename to packages/app/main/src/server/utils/createResponse/createErrorResponse.spec.ts index 3b235a6ac..1154740b6 100644 --- a/packages/emulator/core/src/utils/createResponse/error.spec.ts +++ b/packages/app/main/src/server/utils/createResponse/createErrorResponse.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import createErrorResponse from './error'; +import { createErrorResponse } from './createErrorResponse'; describe('createErrorResponse', () => { it('should create an error response', () => { diff --git a/packages/emulator/core/src/utils/createResponse/error.ts b/packages/app/main/src/server/utils/createResponse/createErrorResponse.ts similarity index 94% rename from packages/emulator/core/src/utils/createResponse/error.ts rename to packages/app/main/src/server/utils/createResponse/createErrorResponse.ts index 89972c6be..7ae2ee2bc 100644 --- a/packages/emulator/core/src/utils/createResponse/error.ts +++ b/packages/app/main/src/server/utils/createResponse/createErrorResponse.ts @@ -33,7 +33,7 @@ import { ErrorResponse } from '@bfemulator/sdk-shared'; -export default function createErrorResponse(code: string, message: string): ErrorResponse { +export function createErrorResponse(code: string, message: string): ErrorResponse { return { error: { code, diff --git a/packages/emulator/core/src/utils/createResponse/resource.spec.ts b/packages/app/main/src/server/utils/createResponse/createResourceResponse.spec.ts similarity index 95% rename from packages/emulator/core/src/utils/createResponse/resource.spec.ts rename to packages/app/main/src/server/utils/createResponse/createResourceResponse.spec.ts index a7106a726..f4f507bf5 100644 --- a/packages/emulator/core/src/utils/createResponse/resource.spec.ts +++ b/packages/app/main/src/server/utils/createResponse/createResourceResponse.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import createResourceResponse from './resource'; +import { createResourceResponse } from './createResourceResponse'; describe('createResourceResponse', () => { it('should create a resource response', () => { diff --git a/packages/emulator/core/src/utils/createResponse/resource.ts b/packages/app/main/src/server/utils/createResponse/createResourceResponse.ts similarity index 95% rename from packages/emulator/core/src/utils/createResponse/resource.ts rename to packages/app/main/src/server/utils/createResponse/createResourceResponse.ts index 6a0e12dd8..8b7f7656f 100644 --- a/packages/emulator/core/src/utils/createResponse/resource.ts +++ b/packages/app/main/src/server/utils/createResponse/createResourceResponse.ts @@ -36,6 +36,6 @@ // import { ResourceResponse } from '@bfemulator/sdk-shared'; -export default function createResourceResponse(id: string): ResourceResponse { +export function createResourceResponse(id: string): ResourceResponse { return { id }; } diff --git a/packages/emulator/core/src/utils/jsonBodyParser.spec.ts b/packages/app/main/src/server/utils/jsonBodyParser.spec.ts similarity index 83% rename from packages/emulator/core/src/utils/jsonBodyParser.spec.ts rename to packages/app/main/src/server/utils/jsonBodyParser.spec.ts index fab9d6f10..9fc301b60 100644 --- a/packages/emulator/core/src/utils/jsonBodyParser.spec.ts +++ b/packages/app/main/src/server/utils/jsonBodyParser.spec.ts @@ -33,7 +33,7 @@ import * as Restify from 'restify'; -import jsonBodyParser from './jsonBodyParser'; +import { createJsonBodyParserMiddleware } from './jsonBodyParser'; let mockBodyParser = jest.fn(() => null); jest.mock('restify', () => ({ @@ -51,27 +51,27 @@ describe('jsonBodyParser', () => { beforeEach(() => { (Restify.plugins.bodyReader as any).mockClear(); (Restify.plugins.jsonBodyParser as any).mockClear(); - bodyParsingFunctions = jsonBodyParser(mockOptions); + bodyParsingFunctions = createJsonBodyParserMiddleware(mockOptions); mockNext.mockClear(); mockBodyParser.mockClear(); }); it('should return a read function that reads a request body', () => { // use default options - bodyParsingFunctions = jsonBodyParser(null); + bodyParsingFunctions = createJsonBodyParserMiddleware(null); expect(bodyParsingFunctions.length).toBe(2); expect(bodyParsingFunctions[0]).toEqual({ bodyReader: true, mapParams: false }); // use supplied options - bodyParsingFunctions = jsonBodyParser(mockOptions); + bodyParsingFunctions = createJsonBodyParserMiddleware(mockOptions); expect(bodyParsingFunctions[0]).toEqual({ bodyReader: true }); }); it('should not parse anything from a HEAD request', () => { const req: any = { method: 'HEAD' }; - const result = jsonBodyParser(mockOptions)[1](req, null, mockNext); + const result = createJsonBodyParserMiddleware(mockOptions)[1](req, null, mockNext); expect(result).toBeUndefined(); expect(mockNext).toHaveBeenCalled(); @@ -80,7 +80,7 @@ describe('jsonBodyParser', () => { it('should not parse anything from a GET request with no requestBodyOnGet option', () => { mockOptions.requestBodyOnGet = false; const req: any = { method: 'GET' }; - const result = jsonBodyParser(mockOptions)[1](req, null, mockNext); + const result = createJsonBodyParserMiddleware(mockOptions)[1](req, null, mockNext); expect(result).toBeUndefined(); expect(mockNext).toHaveBeenCalled(); @@ -92,7 +92,7 @@ describe('jsonBodyParser', () => { contentLength: jest.fn(() => 0), isChunked: jest.fn(() => false), }; - const result = jsonBodyParser(mockOptions)[1](req, null, mockNext); + const result = createJsonBodyParserMiddleware(mockOptions)[1](req, null, mockNext); expect(result).toBeUndefined(); expect(mockNext).toHaveBeenCalled(); @@ -104,7 +104,7 @@ describe('jsonBodyParser', () => { contentLength: jest.fn(() => 1), contentType: jest.fn(() => 'application/json'), }; - const result = jsonBodyParser(mockOptions)[1](req, null, mockNext); + const result = createJsonBodyParserMiddleware(mockOptions)[1](req, null, mockNext); expect(result).toBeUndefined(); expect(mockBodyParser).toHaveBeenCalled(); @@ -117,7 +117,7 @@ describe('jsonBodyParser', () => { contentType: jest.fn(() => 'application/json'), }; mockBodyParser = null; - const result = jsonBodyParser(mockOptions)[1](req, null, mockNext); + const result = createJsonBodyParserMiddleware(mockOptions)[1](req, null, mockNext); expect(result).toBeUndefined(); expect(mockNext).toHaveBeenCalled(); diff --git a/packages/emulator/core/src/utils/jsonBodyParser.ts b/packages/app/main/src/server/utils/jsonBodyParser.ts similarity index 96% rename from packages/emulator/core/src/utils/jsonBodyParser.ts rename to packages/app/main/src/server/utils/jsonBodyParser.ts index b9350db60..76201e718 100644 --- a/packages/emulator/core/src/utils/jsonBodyParser.ts +++ b/packages/app/main/src/server/utils/jsonBodyParser.ts @@ -35,7 +35,7 @@ import * as Restify from 'restify'; const { bodyReader, jsonBodyParser: restifyJsonBodyParser } = Restify.plugins; -export default function jsonBodyParser(options?: any): Restify.RequestHandler[] { +export function createJsonBodyParserMiddleware(options?: any): Restify.RequestHandler[] { options = options || { mapParams: false }; options.bodyReader = true; diff --git a/packages/emulator/core/src/utils/oauthClientEncoder.spec.ts b/packages/app/main/src/server/utils/oauthClientEncoder.spec.ts similarity index 97% rename from packages/emulator/core/src/utils/oauthClientEncoder.spec.ts rename to packages/app/main/src/server/utils/oauthClientEncoder.spec.ts index ac75faa00..26a0054ab 100644 --- a/packages/emulator/core/src/utils/oauthClientEncoder.spec.ts +++ b/packages/app/main/src/server/utils/oauthClientEncoder.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import OAuthClientEncoder from './oauthClientEncoder'; +import { OAuthClientEncoder } from './oauthClientEncoder'; describe('OAuthClientEncoder', () => { it('should initialize with a conversation id', () => { diff --git a/packages/emulator/core/src/utils/oauthClientEncoder.ts b/packages/app/main/src/server/utils/oauthClientEncoder.ts similarity index 95% rename from packages/emulator/core/src/utils/oauthClientEncoder.ts rename to packages/app/main/src/server/utils/oauthClientEncoder.ts index 42a55c9b2..536a33a5c 100644 --- a/packages/emulator/core/src/utils/oauthClientEncoder.ts +++ b/packages/app/main/src/server/utils/oauthClientEncoder.ts @@ -33,9 +33,9 @@ import { Activity, CardAction } from 'botframework-schema'; -import ActivityVisitor from './activityVisitor'; +import { ActivityVisitor } from './activityVisitor'; -export default class OAuthClientEncoder extends ActivityVisitor { +export class OAuthClientEncoder extends ActivityVisitor { public static OAuthEmulatorUrlProtocol: string = 'oauth:'; private _conversationId: string; diff --git a/packages/emulator/core/src/utils/oauthLinkEncoder.spec.ts b/packages/app/main/src/server/utils/oauthLinkEncoder.spec.ts similarity index 95% rename from packages/emulator/core/src/utils/oauthLinkEncoder.spec.ts rename to packages/app/main/src/server/utils/oauthLinkEncoder.spec.ts index f50277064..0276a565c 100644 --- a/packages/emulator/core/src/utils/oauthLinkEncoder.spec.ts +++ b/packages/app/main/src/server/utils/oauthLinkEncoder.spec.ts @@ -33,9 +33,11 @@ import { AttachmentContentTypes } from '@bfemulator/sdk-shared'; -import OAuthLinkEncoder from './oauthLinkEncoder'; +import { OAuthLinkEncoder } from './oauthLinkEncoder'; -jest.mock('./uniqueId', () => () => 'fgfdsggf5432534'); +jest.mock('./uniqueId', () => ({ + uniqueId: () => 'fgfdsggf5432534', +})); const mockArgsSentToFetch = []; let ok = true; @@ -64,10 +66,10 @@ describe('The OauthLinkEncoder', () => { statusText = ''; shouldThrow = false; mockArgsSentToFetch.length = 0; - const emulator = { + const emulatorServer = { getServiceUrl: async () => 'http://localhost', getServiceUrlForOAuth: async () => 'https://ngrok.io/emulator', - facilities: { + state: { conversations: { conversationById: () => ({ codeVerifier: '5432654365475677647655676542524352563457', @@ -80,7 +82,7 @@ describe('The OauthLinkEncoder', () => { }, }; encoder = new OAuthLinkEncoder( - emulator as any, + emulatorServer as any, 'Bearer 54k52n', { attachments: [{ contentType: AttachmentContentTypes.oAuthCard }], diff --git a/packages/emulator/core/src/utils/oauthLinkEncoder.ts b/packages/app/main/src/server/utils/oauthLinkEncoder.ts similarity index 90% rename from packages/emulator/core/src/utils/oauthLinkEncoder.ts rename to packages/app/main/src/server/utils/oauthLinkEncoder.ts index 823117b9a..048f1f481 100644 --- a/packages/emulator/core/src/utils/oauthLinkEncoder.ts +++ b/packages/app/main/src/server/utils/oauthLinkEncoder.ts @@ -37,24 +37,29 @@ import { Attachment, OAuthCard } from 'botframework-schema'; import { AttachmentContentTypes } from '@bfemulator/sdk-shared'; import { Activity } from 'botframework-schema'; -import { BotEmulator } from '../botEmulator'; +import { EmulatorRestServer } from '../restServer'; -import uniqueId from './uniqueId'; +import { uniqueId } from './uniqueId'; -export default class OAuthLinkEncoder { +export class OAuthLinkEncoder { public static OAuthUrlProtocol: string = 'oauthlink:'; public static EmulateOAuthCards: boolean = false; private readonly authorizationHeader: string; private readonly conversationId: string; - private botEmulator: BotEmulator; private activity: Activity; + private emulatorServer: EmulatorRestServer; - constructor(botEmulator: BotEmulator, authorizationHeader: string, activity: Activity, conversationId: string) { + constructor( + emulatorServer: EmulatorRestServer, + authorizationHeader: string, + activity: Activity, + conversationId: string + ) { this.authorizationHeader = authorizationHeader; this.activity = activity; this.conversationId = conversationId; - this.botEmulator = botEmulator; + this.emulatorServer = emulatorServer; } public async resolveOAuthCards(activity: Activity): Promise { @@ -85,7 +90,7 @@ export default class OAuthLinkEncoder { public generateCodeVerifier(conversationId: string): string { const codeVerifier = uniqueId(); - const conversation = this.botEmulator.facilities.conversations.conversationById(conversationId); + const conversation = this.emulatorServer.state.conversations.conversationById(conversationId); conversation.codeVerifier = codeVerifier; return crypto @@ -115,7 +120,7 @@ export default class OAuthLinkEncoder { let errorMessage: string; try { // we need to make sure that the postback url is accessible from the token server (ngrok) - const emulatorUrl = await this.botEmulator.getServiceUrlForOAuth(); + const emulatorUrl = await this.emulatorServer.getServiceUrlForOAuth(); const url = 'https://api.botframework.com/api/botsignin/GetSignInUrl?state=' + state + diff --git a/packages/emulator/core/src/utils/openIdMetadata.spec.ts b/packages/app/main/src/server/utils/openIdMetadata.spec.ts similarity index 99% rename from packages/emulator/core/src/utils/openIdMetadata.spec.ts rename to packages/app/main/src/server/utils/openIdMetadata.spec.ts index 6576bcb09..628f02620 100644 --- a/packages/emulator/core/src/utils/openIdMetadata.spec.ts +++ b/packages/app/main/src/server/utils/openIdMetadata.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import OpenIdMetadata from './openIdMetadata'; +import { OpenIdMetadata } from './openIdMetadata'; jest.mock('base64url', () => ({ toBase64: jest.fn(value => `${value}_base64`), diff --git a/packages/emulator/core/src/utils/openIdMetadata.ts b/packages/app/main/src/server/utils/openIdMetadata.ts similarity index 98% rename from packages/emulator/core/src/utils/openIdMetadata.ts rename to packages/app/main/src/server/utils/openIdMetadata.ts index 9a8bc0e73..b640779a3 100644 --- a/packages/emulator/core/src/utils/openIdMetadata.ts +++ b/packages/app/main/src/server/utils/openIdMetadata.ts @@ -36,7 +36,7 @@ const base64url = require('base64url'); const getPem = require('rsa-pem-from-mod-exp'); /* eslint-enable typescript/no-var-requires */ -export default class OpenIdMetadata { +export class OpenIdMetadata { private lastUpdated = 0; private keys: Key[]; diff --git a/packages/emulator/core/src/utils/paymentEncoder.spec.ts b/packages/app/main/src/server/utils/paymentEncoder.spec.ts similarity index 97% rename from packages/emulator/core/src/utils/paymentEncoder.spec.ts rename to packages/app/main/src/server/utils/paymentEncoder.spec.ts index 13a8f4f69..b17e05014 100644 --- a/packages/emulator/core/src/utils/paymentEncoder.spec.ts +++ b/packages/app/main/src/server/utils/paymentEncoder.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import PaymentEncoder from './paymentEncoder'; +import { PaymentEncoder } from './paymentEncoder'; describe('PaymentEncoder', () => { it('should encode a payment card action', () => { diff --git a/packages/emulator/core/src/utils/paymentEncoder.ts b/packages/app/main/src/server/utils/paymentEncoder.ts similarity index 94% rename from packages/emulator/core/src/utils/paymentEncoder.ts rename to packages/app/main/src/server/utils/paymentEncoder.ts index d4e162c30..5248f981d 100644 --- a/packages/emulator/core/src/utils/paymentEncoder.ts +++ b/packages/app/main/src/server/utils/paymentEncoder.ts @@ -33,9 +33,9 @@ import { CardAction } from 'botframework-schema'; -import ActivityVisitor from './activityVisitor'; +import { ActivityVisitor } from './activityVisitor'; -export default class PaymentEncoder extends ActivityVisitor { +export class PaymentEncoder extends ActivityVisitor { public static PaymentEmulatorUrlProtocol: string = 'payment:'; protected visitCardAction(cardAction: CardAction) { diff --git a/packages/emulator/core/src/utils/safeStringify.ts b/packages/app/main/src/server/utils/safeStringify.ts similarity index 95% rename from packages/emulator/core/src/utils/safeStringify.ts rename to packages/app/main/src/server/utils/safeStringify.ts index 17da24de6..04c350515 100644 --- a/packages/emulator/core/src/utils/safeStringify.ts +++ b/packages/app/main/src/server/utils/safeStringify.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -export default function safeStringify(o: any, space?: string | number): string { +export function safeStringify(o: any, space?: string | number): string { const cache = []; if (typeof o !== 'object') { diff --git a/packages/emulator/core/src/utils/sendErrorResponse.spec.ts b/packages/app/main/src/server/utils/sendErrorResponse.spec.ts similarity index 95% rename from packages/emulator/core/src/utils/sendErrorResponse.spec.ts rename to packages/app/main/src/server/utils/sendErrorResponse.spec.ts index 82196a6bc..9689d60eb 100644 --- a/packages/emulator/core/src/utils/sendErrorResponse.spec.ts +++ b/packages/app/main/src/server/utils/sendErrorResponse.spec.ts @@ -34,8 +34,8 @@ import { ErrorCodes } from '@bfemulator/sdk-shared'; import * as HttpStatus from 'http-status-codes'; -import sendErrorResponse from './sendErrorResponse'; -import createErrorResponse from './createResponse/error'; +import { sendErrorResponse } from './sendErrorResponse'; +import { createErrorResponse } from './createResponse/createErrorResponse'; describe('sendErrorResponse', () => { const mockSend = jest.fn(() => {}); diff --git a/packages/emulator/core/src/utils/sendErrorResponse.ts b/packages/app/main/src/server/utils/sendErrorResponse.ts similarity index 95% rename from packages/emulator/core/src/utils/sendErrorResponse.ts rename to packages/app/main/src/server/utils/sendErrorResponse.ts index 23da7f3e7..b067b966e 100644 --- a/packages/emulator/core/src/utils/sendErrorResponse.ts +++ b/packages/app/main/src/server/utils/sendErrorResponse.ts @@ -35,7 +35,7 @@ import { APIException, ErrorCodes, ErrorResponse } from '@bfemulator/sdk-shared' import * as HttpStatus from 'http-status-codes'; import * as Restify from 'restify'; -import createErrorResponse from './createResponse/error'; +import { createErrorResponse } from './createResponse/createErrorResponse'; function exceptionToAPIException(exception: any): APIException { if (exception.error && exception.statusCode) { @@ -48,7 +48,7 @@ function exceptionToAPIException(exception: any): APIException { } } -export default function sendErrorResponse( +export function sendErrorResponse( req: Restify.Request, res: Restify.Response, next: Restify.Next, diff --git a/packages/emulator/core/src/utils/statusCodeFamily.spec.ts b/packages/app/main/src/server/utils/statusCodeFamily.spec.ts similarity index 96% rename from packages/emulator/core/src/utils/statusCodeFamily.spec.ts rename to packages/app/main/src/server/utils/statusCodeFamily.spec.ts index 6d118f789..49e38cfca 100644 --- a/packages/emulator/core/src/utils/statusCodeFamily.spec.ts +++ b/packages/app/main/src/server/utils/statusCodeFamily.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import statusCodeFamily from './statusCodeFamily'; +import { statusCodeFamily } from './statusCodeFamily'; describe('statusCodeFamily', () => { it('should return whether a status code is within the expected family', () => { diff --git a/packages/emulator/core/src/utils/statusCodeFamily.ts b/packages/app/main/src/server/utils/statusCodeFamily.ts similarity index 94% rename from packages/emulator/core/src/utils/statusCodeFamily.ts rename to packages/app/main/src/server/utils/statusCodeFamily.ts index 702d92610..e127c88d7 100644 --- a/packages/emulator/core/src/utils/statusCodeFamily.ts +++ b/packages/app/main/src/server/utils/statusCodeFamily.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -export default function statusCodeFamily(statusCode: number | string, expectedFamily: number) { +export function statusCodeFamily(statusCode: number | string, expectedFamily: number) { if (typeof statusCode === 'string') { statusCode = +statusCode; } diff --git a/packages/emulator/core/src/utils/stringProvider.ts b/packages/app/main/src/server/utils/stringProvider.ts similarity index 100% rename from packages/emulator/core/src/utils/stringProvider.ts rename to packages/app/main/src/server/utils/stringProvider.ts diff --git a/packages/emulator/core/src/utils/uniqueId.spec.ts b/packages/app/main/src/server/utils/uniqueId.spec.ts similarity index 97% rename from packages/emulator/core/src/utils/uniqueId.spec.ts rename to packages/app/main/src/server/utils/uniqueId.spec.ts index 6aaa40170..c8df5905b 100644 --- a/packages/emulator/core/src/utils/uniqueId.spec.ts +++ b/packages/app/main/src/server/utils/uniqueId.spec.ts @@ -31,7 +31,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -import uniqueId from './uniqueId'; +import { uniqueId } from './uniqueId'; describe('uniqueId', () => { it('should generate unique ids', () => { diff --git a/packages/emulator/core/src/utils/uniqueId.ts b/packages/app/main/src/server/utils/uniqueId.ts similarity index 97% rename from packages/emulator/core/src/utils/uniqueId.ts rename to packages/app/main/src/server/utils/uniqueId.ts index 3ee00869e..98306e1c3 100644 --- a/packages/emulator/core/src/utils/uniqueId.ts +++ b/packages/app/main/src/server/utils/uniqueId.ts @@ -33,6 +33,6 @@ import uuidv1 from 'uuid/v1'; -export default function uniqueId(): string { +export function uniqueId(): string { return uuidv1().toString(); } diff --git a/packages/app/main/src/state/actions/windowStateActions.spec.ts b/packages/app/main/src/state/actions/windowStateActions.spec.ts index 2b0af51ee..2c1320598 100644 --- a/packages/app/main/src/state/actions/windowStateActions.spec.ts +++ b/packages/app/main/src/state/actions/windowStateActions.spec.ts @@ -66,7 +66,10 @@ describe('Window state actions', () => { }); test('setAvailableThemes action', () => { - const themes = [{ name: 'light', href: './light.css' }, { name: 'dark', href: './dark.css' }]; + const themes = [ + { name: 'light', href: './light.css' }, + { name: 'dark', href: './dark.css' }, + ]; expect(windowStateActions.setAvailableThemes(themes)).toEqual({ type: windowStateActions.SET_AVAILABLE_THEMES, payload: { availableThemes: themes }, diff --git a/packages/app/main/src/state/reducers/users.spec.ts b/packages/app/main/src/state/reducers/users.spec.ts index 7a32ac4f6..18de8a282 100644 --- a/packages/app/main/src/state/reducers/users.spec.ts +++ b/packages/app/main/src/state/reducers/users.spec.ts @@ -54,7 +54,11 @@ describe('users reducer', () => { user1: {}, }, }; - const action = addUsers([{ name: '', id: 'user1' }, { name: '', id: 'user2' }, { name: '', id: 'user3' }]); + const action = addUsers([ + { name: '', id: 'user1' }, + { name: '', id: 'user2' }, + { name: '', id: 'user3' }, + ]); const state = users(initialState, action); expect(state).toEqual({ diff --git a/packages/app/main/src/state/reducers/windowState.spec.ts b/packages/app/main/src/state/reducers/windowState.spec.ts index 34cc95cf6..031696b73 100644 --- a/packages/app/main/src/state/reducers/windowState.spec.ts +++ b/packages/app/main/src/state/reducers/windowState.spec.ts @@ -65,7 +65,10 @@ describe('windowState reducer', () => { }); it('should handle a set available themes action', () => { - const themes = [{ name: 'light', href: './light.css' }, { name: 'dark', href: './dark.css' }]; + const themes = [ + { name: 'light', href: './light.css' }, + { name: 'dark', href: './dark.css' }, + ]; const action = setAvailableThemes(themes); const state = windowState({} as any, action); diff --git a/packages/app/main/src/state/sagas/settingsSagas.ts b/packages/app/main/src/state/sagas/settingsSagas.ts index 6c244f666..1c2edd79a 100644 --- a/packages/app/main/src/state/sagas/settingsSagas.ts +++ b/packages/app/main/src/state/sagas/settingsSagas.ts @@ -35,11 +35,11 @@ import { call, ForkEffect, select, takeEvery } from 'redux-saga/effects'; import { app } from 'electron'; import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared'; -import { Emulator } from '../../emulator'; import { FrameworkAction, FrameworkActionType } from '../actions/frameworkSettingsActions'; import { REMEMBER_THEME } from '../actions/windowStateActions'; import { ADD_SAVED_BOT_URL } from '../actions/savedBotUrlsActions'; import { RootState } from '../store'; +import { Emulator } from '../../emulator'; const getAvailableThemes = (state: RootState) => state.settings.windowState.availableThemes; const getCurrentTheme = (state: RootState) => state.settings.windowState.theme; @@ -62,7 +62,7 @@ export class SettingsSagas { public static *setFramework(action: FrameworkAction): IterableIterator { const emulator = Emulator.getInstance(); yield emulator.ngrok.updateNgrokFromSettings(action.payload); - emulator.framework.server.botEmulator.facilities.locale = action.payload.locale; + //emulator.framework.server.botEmulator.facilities.locale = action.payload.locale; yield* SettingsSagas.pushClientAwareSettings(); } @@ -81,7 +81,7 @@ export class SettingsSagas { SharedConstants.Commands.Settings.ReceiveGlobalSettings, { appPath: app.getAppPath(), - serverUrl: (Emulator.getInstance().framework.serverUrl || '').replace('[::]', 'localhost'), + serverUrl: (Emulator.getInstance().server.serverUrl || '').replace('[::]', 'localhost'), cwd: (process.cwd() || '').replace(/\\/g, '/'), users: settingsState.users, locale: settingsState.framework.locale, diff --git a/packages/app/main/src/utils/getLocalhostServiceUrl.spec.ts b/packages/app/main/src/utils/getLocalhostServiceUrl.spec.ts index 8ced9c2a5..745ca8f60 100644 --- a/packages/app/main/src/utils/getLocalhostServiceUrl.spec.ts +++ b/packages/app/main/src/utils/getLocalhostServiceUrl.spec.ts @@ -36,7 +36,7 @@ import { getLocalhostServiceUrl } from './getLocalhostServiceUrl'; jest.mock('../emulator', () => ({ Emulator: { getInstance: () => ({ - framework: { + server: { serverUrl: '[::]:52638', }, }), diff --git a/packages/app/main/src/utils/getLocalhostServiceUrl.ts b/packages/app/main/src/utils/getLocalhostServiceUrl.ts index 30fa98ed1..5b71235da 100644 --- a/packages/app/main/src/utils/getLocalhostServiceUrl.ts +++ b/packages/app/main/src/utils/getLocalhostServiceUrl.ts @@ -34,5 +34,5 @@ import { Emulator } from '../emulator'; export function getLocalhostServiceUrl(): string { - return Emulator.getInstance().framework.serverUrl.replace('[::]', 'localhost'); + return Emulator.getInstance().server.serverUrl.replace('[::]', 'localhost'); } diff --git a/packages/app/main/src/utils/openFileFromCommandLine.spec.ts b/packages/app/main/src/utils/openFileFromCommandLine.spec.ts index b9f1dac4a..2d966139d 100644 --- a/packages/app/main/src/utils/openFileFromCommandLine.spec.ts +++ b/packages/app/main/src/utils/openFileFromCommandLine.spec.ts @@ -92,7 +92,10 @@ describe('The openFileFromCommandLine util', () => { it('should make the appropriate calls to open a .bot file', async () => { await openFileFromCommandLine('some/path.bot', commandService); - expect(commandService.localCalls).toEqual([['bot:open', 'some/path.bot'], ['bot:set-active', null]]); + expect(commandService.localCalls).toEqual([ + ['bot:open', 'some/path.bot'], + ['bot:set-active', null], + ]); expect(commandService.remoteCalls).toEqual([['bot:load', null]]); }); diff --git a/packages/emulator/cli/.babelrc b/packages/emulator/cli/.babelrc deleted file mode 100644 index c11cefaec..000000000 --- a/packages/emulator/cli/.babelrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "node": "8" - } - } - ], - "@babel/preset-typescript" - ], - "ignore": [ - "**/*.d.ts" - ], - "sourceMaps": "inline", - "plugins": [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-transform-react-jsx", - "@babel/plugin-transform-runtime" - ] -} diff --git a/packages/emulator/cli/.eslintrc.js b/packages/emulator/cli/.eslintrc.js deleted file mode 100644 index b6f7dbaa9..000000000 --- a/packages/emulator/cli/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: '../../../.eslintrc.js', - rules: { - 'no-console': 'off', - }, -}; diff --git a/packages/emulator/cli/.gitignore b/packages/emulator/cli/.gitignore deleted file mode 100644 index fda8f74e8..000000000 --- a/packages/emulator/cli/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/.env -/bots.json -/coverage -/lib -/node_modules diff --git a/packages/emulator/cli/package-lock.json b/packages/emulator/cli/package-lock.json deleted file mode 100644 index bdf2c632f..000000000 --- a/packages/emulator/cli/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@bfemulator/emulator-cli", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "dotenv": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" - } - } -} diff --git a/packages/emulator/cli/package.json b/packages/emulator/cli/package.json deleted file mode 100644 index 50ab31eb5..000000000 --- a/packages/emulator/cli/package.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "name": "@bfemulator/emulator-cli", - "version": "1.0.0", - "description": "", - "bin": { - "bfemulator": "lib/index.js" - }, - "files": [ - "lib/**/*.js" - ], - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "babel ./src --out-dir lib --extensions \".ts,.tsx\" --ignore \"**/*.spec.ts\" && tsc --emitDeclarationOnly", - "clean": "rimraf lib", - "lint": "eslint --color --quiet --ext .js,.jsx,.ts,.tsx ./src", - "lint:fix": "npm run lint -- --fix", - "start": "node-dev .", - "test": "jest", - "typecheck": "tsc" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Microsoft/BotFramework-Emulator.git" - }, - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/Microsoft/BotFramework-Emulator/issues" - }, - "homepage": "https://github.com/Microsoft/BotFramework-Emulator#readme", - "jest": { - "moduleFileExtensions": [ - "js", - "ts" - ], - "testMatch": [ - "**/__tests__/**/*.[jt]s?(x)", - "**/?(*.)(spec|test).[jt]s?(x)" - ], - "transform": { - "^.+\\.[jt]sx?$": "babel-jest" - } - }, - "dependencies": { - "@babel/runtime": "^7.1.5", - "@bfemulator/emulator-core": "^1.0.0-0", - "@bfemulator/sdk-shared": "^1.0.0", - "commander": "^2.15.1", - "debug": "^3.1.0", - "dotenv": "^5.0.1", - "get-port": "^3.2.0", - "npmlog": "^4.1.2", - "restify": "^5.0.0", - "restify-cors-middleware": "^1.1.0" - }, - "devDependencies": { - "@babel/cli": "^7.1.0", - "@babel/core": "^7.1.0", - "@babel/plugin-proposal-class-properties": "^7.1.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-runtime": "^7.4.4", - "@babel/preset-env": "^7.1.0", - "@babel/preset-typescript": "^7.1.0", - "@types/jest": "24.0.13", - "@types/node": "8.9.3", - "@types/restify": "^5.0.7", - "babel-core": "^7.0.0-bridge.0", - "babel-jest": "24.8.0", - "concurrently": "^3.5.1", - "eslint": "^5.12.0", - "eslint-config-prettier": "^3.5.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-notice": "^0.7.7", - "eslint-plugin-prettier": "^3.0.1", - "eslint-plugin-typescript": "^1.0.0-rc.3", - "jest": "24.8.0", - "node-dev": "^3.1.3", - "rimraf": "^2.6.2", - "typescript": "3.1.1" - } -} diff --git a/packages/emulator/cli/src/index.ts b/packages/emulator/cli/src/index.ts deleted file mode 100644 index 4f3dfc95b..000000000 --- a/packages/emulator/cli/src/index.ts +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env node - -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { readFile } from 'fs'; - -import { BotEmulator } from '@bfemulator/emulator-core'; -import { config } from 'dotenv'; -import getPort from 'get-port'; -import * as Restify from 'restify'; -import CORS from 'restify-cors-middleware'; - -import NpmLogger from './npmLogger'; - -/* eslint-disable typescript/no-var-requires */ -const program = require('commander'); - -const packageJSON = require('../package.json'); -/* eslint-enable typescript/no-var-requires */ - -config(); - -program - // .command('bfemulator') - .version(packageJSON.version) - .option('-p, --port ', 'port number for Direct Line service', 5000) - .option('-I, --app-id ', 'Microsoft Application ID, will override environment "MICROSOFT_APP_ID"') - .option( - '-P, --app-password ', - 'Microsoft Application Password, will override environment ' + '"MICROSOFT_APP_PASSWORD"' - ) - .option('-s, --service-url ', 'URL for the bot to callback', 'http://localhost:5000') - .option('-u, --bot-url ', 'URL to connect to bot', 'http://localhost:3978/api/messages/') - .option('--bot-id ', 'bot ID', 'bot-1') - .option('--use-10-tokens', 'use version 1.0 authentication tokens', false) - .option('-f, --file ', 'read endpoints from file') - .on('--help', () => { - console.log(); - console.log(' Notes:'); - console.log(); - console.log( - ' Use bots.json file to host multiple bots. Put MSA App ID as Direct Line secret to' + - ' point to different bots.' - ); - console.log(); - console.log(' Using bots.json file will override endpoint defined thru --port and --bot-url.'); - console.log(); - }) - .parse(process.argv); - -// TODO: Support multi bot from file - -program.appId = program.appId || process.env.MICROSOFT_APP_ID; -program.appPassword = program.appPassword || process.env.MICROSOFT_APP_PASSWORD; - -async function main() { - // Create a Restify server - const server = Restify.createServer({ - name: 'localmode', - }); - - // Setup CORS middleware for the whole server - const cors = CORS({ - origins: ['*'], - allowHeaders: ['authorization', 'x-requested-with'], - exposeHeaders: [], - }); - - server.pre(cors.preflight); - server.use(cors.actual); - - // Get a port number, we need this to construct `serviceUrl` - const port = program.port || (await getPort(5000)); - - // Create a bot entry - const bot = new BotEmulator( - async () => program.serviceUrl, - () => program.serviceUrl, - () => null || `http://localhost:${port}`, - { - loggerOrLogService: new NpmLogger(), - } - ); - - if (program.file) { - const botsJSON = await new Promise((resolve, reject) => { - readFile(program.file, { encoding: 'utf8' }, (err, result) => (err ? reject(err) : resolve(result))); - }); - - const botEndpoints = JSON.parse(botsJSON); - - botEndpoints.forEach(endpoint => bot.facilities.endpoints.push(endpoint.botUrl, endpoint)); - } else { - bot.facilities.endpoints.push(program.botUrl, { - botId: program.botId, - botUrl: program.botUrl, - msaAppId: program.appId, - msaPassword: program.appPassword, - use10Tokens: program.use10Tokens, - }); - } - - // Mount bot routes on the server - bot.mount(server); - - const endpoints = bot.facilities.endpoints.getAll(); - const urls = Object.keys(endpoints) - .reduce((endpoint, key) => [...endpoint, endpoints[key].botUrl], []) - .sort(); - - // Start listening - server.listen(port, () => { - console.log(`${server.name} listening on ${server.url} with bot on ${urls.join(', ')}`); - console.log(`The bot will callback on ${program.serviceUrl}`); - }); -} - -main(); diff --git a/packages/emulator/cli/tsconfig.json b/packages/emulator/cli/tsconfig.json deleted file mode 100644 index 85653a72a..000000000 --- a/packages/emulator/cli/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "build/dist", - "declarationDir": "lib" - }, - "include": ["./src"] -} diff --git a/packages/emulator/core/.babelrc b/packages/emulator/core/.babelrc deleted file mode 100644 index 97bad7460..000000000 --- a/packages/emulator/core/.babelrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "node": "8" - } - } - ], - "@babel/preset-typescript" - ], - "ignore": [ - "**/*.d.ts" - ], - "plugins": [ - "@babel/proposal-class-properties", - "@babel/plugin-transform-runtime" - ] -} diff --git a/packages/emulator/core/.eslintrc.js b/packages/emulator/core/.eslintrc.js deleted file mode 100644 index 65e23b71c..000000000 --- a/packages/emulator/core/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: '../../../.eslintrc.js', -}; diff --git a/packages/emulator/core/.gitignore b/packages/emulator/core/.gitignore deleted file mode 100644 index 38c4055aa..000000000 --- a/packages/emulator/core/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/.env -/coverage -/lib -/node_modules diff --git a/packages/emulator/core/package-lock.json b/packages/emulator/core/package-lock.json deleted file mode 100644 index a23577e9a..000000000 --- a/packages/emulator/core/package-lock.json +++ /dev/null @@ -1,8607 +0,0 @@ -{ - "name": "@bfemulator/emulator-core", - "version": "1.0.0-0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@azure/ms-rest-js": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.2.6.tgz", - "integrity": "sha512-8cmDpxsQjVdveJwYKtNnkJorxEORLYJu9UHaUvLZA6yHExzDeISHAcSVWE0J05+VkJtqheVHF17M+2ro18Cdnw==", - "requires": { - "axios": "^0.18.0", - "form-data": "^2.3.2", - "tough-cookie": "^2.4.3", - "tslib": "^1.9.2", - "uuid": "^3.2.1", - "xml2js": "^0.4.19" - } - }, - "@babel/cli": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.6.2.tgz", - "integrity": "sha512-JDZ+T/br9pPfT2lmAMJypJDTTTHM9ePD/ED10TRjRzJVdEVy+JB3iRlhzYmTt5YkNgHvxWGlUVnLtdv6ruiDrQ==", - "dev": true, - "requires": { - "chokidar": "^2.1.8", - "commander": "^2.8.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "lodash": "^4.17.13", - "mkdirp": "^0.5.1", - "output-file-sync": "^2.0.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" - } - }, - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.2.tgz", - "integrity": "sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.2", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz", - "integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==", - "dev": true, - "requires": { - "@babel/types": "^7.6.0", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-builder-react-jsx": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", - "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0", - "esutils": "^2.0.0" - } - }, - "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.6.0.tgz", - "integrity": "sha512-O1QWBko4fzGju6VoVvrZg0RROCVifcLxiApnGP3OWfWzvxRZFCoBD81K5ur5e3bVY2Vf/5rIJm8cqPKn8HUJng==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4" - } - }, - "@babel/helper-define-map": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", - "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.5.5", - "lodash": "^4.17.13" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", - "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", - "dev": true, - "requires": { - "@babel/types": "^7.5.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", - "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", - "dev": true, - "requires": { - "lodash": "^4.17.13" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", - "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" - } - }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", - "dev": true, - "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" - } - }, - "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", - "dev": true, - "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz", - "integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz", - "integrity": "sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.5.5", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", - "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz", - "integrity": "sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", - "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", - "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", - "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", - "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", - "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.2.tgz", - "integrity": "sha512-zZT8ivau9LOQQaOGC7bQLQOT4XPkPXgN2ERfUgk1X8ql+mVkLc4E8eKk+FO3o0154kxzqenWCorfmEXpEZcrSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.13" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", - "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.5.5", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", - "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", - "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", - "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", - "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", - "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", - "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.2.tgz", - "integrity": "sha512-xBdB+XOs+lgbZc2/4F5BVDVcDNS4tcSKQc96KmlqLEAwz6tpYPEvPdmDfvVG0Ssn8lAhronaRs6Z6KSexIpK5g==", - "dev": true, - "requires": { - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", - "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", - "dev": true, - "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", - "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", - "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", - "dev": true, - "requires": { - "@babel/helper-builder-react-jsx": "^7.3.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", - "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.6.2.tgz", - "integrity": "sha512-cqULw/QB4yl73cS5Y0TZlQSjDvNkzDbu0FurTZyHlJpWE5T3PCMdnyV+xXoH1opr1ldyHODe3QAX3OMAii5NxA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz", - "integrity": "sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.0.tgz", - "integrity": "sha512-yzw7EopOOr6saONZ3KA3lpizKnWRTe+rfBqg4AmQbSow7ik7fqmzrfIqt053osLwLE2AaTqGinLM2tl6+M/uog==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.6.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-typescript": "^7.2.0" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", - "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/preset-env": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.2.tgz", - "integrity": "sha512-Ru7+mfzy9M1/YTEtlDS8CD45jd22ngb9tXnn64DvQK3ooyqSw9K4K9DUWmYknTTVk4TqygL9dqCrZgm1HMea/Q==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-dynamic-import": "^7.5.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.6.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.6.2", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.5.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.6.2", - "@babel/plugin-transform-classes": "^7.5.5", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.6.0", - "@babel/plugin-transform-dotall-regex": "^7.6.2", - "@babel/plugin-transform-duplicate-keys": "^7.5.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.5.0", - "@babel/plugin-transform-modules-commonjs": "^7.6.0", - "@babel/plugin-transform-modules-systemjs": "^7.5.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.2", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.5.5", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.6.2", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.6.2", - "@babel/types": "^7.6.0", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - } - }, - "@babel/preset-typescript": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.6.0.tgz", - "integrity": "sha512-4xKw3tTcCm0qApyT6PqM9qniseCE79xGHiUnNdKGdxNsGUc2X7WwZybqIpnTmoukg3nhPceI5KPNzNqLNeIJww==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.6.0" - } - }, - "@babel/runtime": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", - "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz", - "integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.2", - "@babel/types": "^7.6.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/bunyan": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.6.tgz", - "integrity": "sha512-YiozPOOsS6bIuz31ilYqR5SlLif4TBWsousN2aCWLi5233nZSX19tFbcQUPdR7xJ8ypPyxkCGNxg0CIV5n9qxQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.0.13", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.13.tgz", - "integrity": "sha512-3m6RPnO35r7Dg+uMLj1+xfZaOgIHHHut61djNjzwExXN4/Pm9has9C6I1KMYSfz7mahDhWUOVg4HW/nZdv5Pww==", - "dev": true, - "requires": { - "@types/jest-diff": "*" - } - }, - "@types/jest-diff": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", - "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", - "dev": true - }, - "@types/jsonwebtoken": { - "version": "7.2.8", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-7.2.8.tgz", - "integrity": "sha512-XENN3YzEB8D6TiUww0O8SRznzy1v+77lH7UmuN54xq/IHIsyWjWOzZuFFTtoiRuaE782uAoRwBe/wwow+vQXZw==", - "requires": { - "@types/node": "*" - }, - "dependencies": { - "@types/node": { - "version": "12.7.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz", - "integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==" - } - } - }, - "@types/node": { - "version": "8.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.3.tgz", - "integrity": "sha512-wqrPE4Uvj2fmL0E5JFQiY7D/5bAKvVUfWTnQ5NEV35ULkAU0j3QuqIi9Qyrytz8M5hsrh8Kijt+FsdLQaZR+IA==", - "dev": true - }, - "@types/restify": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@types/restify/-/restify-5.0.11.tgz", - "integrity": "sha512-UQposjIQewSD4c4gvvW/3kyhAX4RF/rIcoivFYRrRF4km9phHK6PaiST+Ueau5Lq/4b3XYt6iGgzwTxn645PQw==", - "dev": true, - "requires": { - "@types/bunyan": "*", - "@types/node": "*", - "@types/spdy": "*" - } - }, - "@types/spdy": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@types/spdy/-/spdy-3.4.4.tgz", - "integrity": "sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true - }, - "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", - "dev": true - }, - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - } - }, - "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", - "dev": true - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" - } - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true, - "optional": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, - "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, - "babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true - }, - "babel-jest": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.8.0.tgz", - "integrity": "sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw==", - "dev": true, - "requires": { - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.6.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.0.tgz", - "integrity": "sha512-LIVmqIrIWuiqTvn4RzcrwCOuHo2DD6tKmKBPXXlr4p4n4l6BZBkwFTIa3zu1XkX5MbZgro4a6BvPi+n2Mns5Gg==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "optional": true - }, - "botframework-connector": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/botframework-connector/-/botframework-connector-4.5.3.tgz", - "integrity": "sha512-a98+yMnTbTr2C6KwVPf30z72ieXrHDkP5BH48IZz6qi7Z828jDG6cSwZsbqlA9ot2ETK4UWXKERVik7XpYcdvQ==", - "requires": { - "@azure/ms-rest-js": "1.2.6", - "@types/jsonwebtoken": "7.2.8", - "@types/node": "^10.12.18", - "base64url": "^3.0.0", - "botframework-schema": "^4.5.3", - "form-data": "^2.3.3", - "jsonwebtoken": "8.0.1", - "nock": "^10.0.3", - "node-fetch": "^2.2.1", - "rsa-pem-from-mod-exp": "^0.8.4" - }, - "dependencies": { - "@types/node": { - "version": "10.14.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.19.tgz", - "integrity": "sha512-j6Sqt38ssdMKutXBUuAcmWF8QtHW1Fwz/mz4Y+Wd9mzpBiVFirjpNQf363hG5itkG+yGaD+oiLyb50HxJ36l9Q==" - }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, - "jsonwebtoken": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.0.1.tgz", - "integrity": "sha1-UNrvjQqMfeLNBrwQE7dbBMzz8M8=", - "requires": { - "jws": "^3.1.4", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.0.0", - "xtend": "^4.0.1" - } - } - } - }, - "botframework-schema": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/botframework-schema/-/botframework-schema-4.5.3.tgz", - "integrity": "sha512-Tf9obp0/qdhhx1+YmAQPt+RkqWyULPcj2/XPd4kFhKNo80afsLI3ZN7kJdfw+PitSQDisxjmQ+r2rdt0q2jMtw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "browserslist": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", - "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000989", - "electron-to-chromium": "^1.3.247", - "node-releases": "^1.1.29" - } - }, - "bser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", - "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "bunyan": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", - "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", - "dev": true, - "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.10.6", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } - } - }, - "caniuse-lite": { - "version": "1.0.30000997", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000997.tgz", - "integrity": "sha512-BQLFPIdj2ntgBNWp9Q64LGUIEmvhKkzzHhUHR3CD5A9Lb7ZKF20/+sgadhFap69lk5XmK1fTUleDclaRFvgVUA==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", - "dev": true, - "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "dev": true, - "requires": { - "colors": "1.0.3" - } - }, - "cli-usage": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.10.tgz", - "integrity": "sha512-Q/s1S4Jz5LYI0LQ+XiFQCXkhMzn244ddyIffni8JIq/kL95DvQomVQ0cJC41c76hH9/FmZGY7rZB53y/bXHtRA==", - "dev": true, - "requires": { - "marked": "^0.7.0", - "marked-terminal": "^3.3.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "clone-regexp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.1.tgz", - "integrity": "sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw==", - "dev": true, - "requires": { - "is-regexp": "^1.0.0", - "is-supported-regexp-flag": "^1.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concurrently": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.1.tgz", - "integrity": "sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "commander": "2.6.0", - "date-fns": "^1.23.0", - "lodash": "^4.5.1", - "read-pkg": "^3.0.0", - "rx": "2.3.24", - "spawn-command": "^0.0.2-1", - "supports-color": "^3.2.3", - "tree-kill": "^1.1.0" - }, - "dependencies": { - "commander": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=", - "dev": true - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js-compat": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", - "integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==", - "dev": true, - "requires": { - "browserslist": "^4.6.6", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "csv": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/csv/-/csv-1.2.1.tgz", - "integrity": "sha1-UjHt/BxxUlEuxFeBB2p6l/9SXAw=", - "dev": true, - "requires": { - "csv-generate": "^1.1.2", - "csv-parse": "^1.3.3", - "csv-stringify": "^1.1.2", - "stream-transform": "^0.2.2" - } - }, - "csv-generate": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-1.1.2.tgz", - "integrity": "sha1-7GsA7a7W5ZrZwgWC9MNk4osUYkA=", - "dev": true - }, - "csv-parse": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.3.3.tgz", - "integrity": "sha1-0c/YdDwvhJoKuy/VRNtWaV0ZpJA=", - "dev": true - }, - "csv-stringify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-1.1.2.tgz", - "integrity": "sha1-d6QVJlgbzjOA8SsA18W7rHDIK1g=", - "dev": true, - "requires": { - "lodash.get": "~4.4.2" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", - "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - }, - "dependencies": { - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - } - } - }, - "debounce": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", - "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==", - "dev": true - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.0.tgz", - "integrity": "sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", - "dev": true - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.14.0" - } - }, - "dynamic-dedupe": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.2.0.tgz", - "integrity": "sha1-UPfChoSDHs8cFwqrZ6HVMRzdds4=", - "dev": true, - "requires": { - "xtend": "~2.0.6" - }, - "dependencies": { - "object-keys": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.2.0.tgz", - "integrity": "sha1-zd7AKZiwkb5CvxA1rjLknxy26mc=", - "dev": true, - "requires": { - "foreach": "~2.0.1", - "indexof": "~0.0.1", - "is": "~0.2.6" - } - }, - "xtend": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.0.6.tgz", - "integrity": "sha1-XqZXptukRwacLlnFihE4ywxebO4=", - "dev": true, - "requires": { - "is-object": "~0.1.2", - "object-keys": "~0.2.0" - } - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "electron-to-chromium": { - "version": "1.3.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.267.tgz", - "integrity": "sha512-9Q2ixAJC+oHjWNtJV0MQ4vJMCWSowIrC6V6vcr+bwPddTDHj2ddv9xxXCzf4jT/fy6HP7maPoW0gifXkRxCttQ==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-regexp-component": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", - "integrity": "sha1-nGO20LJf8qiMOtvRjFthrMO5+qI=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "eslint-config-prettier": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz", - "integrity": "sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", - "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", - "dev": true, - "requires": { - "debug": "^2.6.8", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", - "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.11.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } - } - }, - "eslint-plugin-notice": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-notice/-/eslint-plugin-notice-0.7.8.tgz", - "integrity": "sha512-a18VwxiBp4TmXRVpx7T5D4ilHnMS1Gq/5OMUriCcJGHD72Cbji7qVk19DGOW9vBHnJJKeg0yU95a7/o8JQoMCw==", - "dev": true, - "requires": { - "find-root": "^1.1.0", - "lodash": ">=2.4.0", - "metric-lcs": "^0.1.2" - } - }, - "eslint-plugin-prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.1.tgz", - "integrity": "sha512-A+TZuHZ0KU0cnn56/9mfR7/KjUJ9QNVXUhwvRFSR7PGPe0zQR6PTkmyqg1AtUUEOzTqeRsUwyKFh0oVZKVCrtA==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-plugin-typescript": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-typescript/-/eslint-plugin-typescript-1.0.0-rc.3.tgz", - "integrity": "sha512-urXH7sKqRkFLcDj6dP3tvQALfWIRGn8J8Kg9dYSoavXvy62FxfUv6JgjDAHQZudi9fSRQpEZA/LqdJXDOwKHPA==", - "dev": true, - "requires": { - "requireindex": "^1.2.0", - "typescript-eslint-parser": "21.0.2" - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.0.0" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.0.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.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" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "filewatcher": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/filewatcher/-/filewatcher-3.0.1.tgz", - "integrity": "sha1-9KGVc1Xdr0Q8zXiolfPVXiPIoDQ=", - "dev": true, - "requires": { - "debounce": "^1.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", - "dev": true - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "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" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "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" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "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" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "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" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", - "dev": true - }, - "handlebars": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz", - "integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "http-status-codes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-1.3.2.tgz", - "integrity": "sha512-nDUtj0ltIt08tGi2VWSpSzNNFye0v3YSe9lX3lIqLTuVvvRiYCvs4QQBSHo0eomFYw1wlUuofurUAlTm+vHnXg==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - } - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/is/-/is-0.2.7.tgz", - "integrity": "sha1-OzSixI81mXLzUEKEkZOucmS2NWI=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "optional": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-object": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-0.1.2.tgz", - "integrity": "sha1-AO+8CIFsM8/ErIJR0TLhDcZQmNc=", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-supported-regexp-flag": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz", - "integrity": "sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "jest": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.8.0.tgz", - "integrity": "sha512-o0HM90RKFRNWmAWvlyV8i5jGZ97pFwkeVoGvPW1EtLTgJc2+jcuqcbbqcSZLE/3f2S5pt0y2ZBETuhpWNl1Reg==", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.8.0" - }, - "dependencies": { - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - }, - "dependencies": { - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } - } - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - } - }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", - "dev": true - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash._arraycopy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", - "dev": true - }, - "lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", - "dev": true - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash._baseclone": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", - "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", - "dev": true, - "requires": { - "lodash._arraycopy": "^3.0.0", - "lodash._arrayeach": "^3.0.0", - "lodash._baseassign": "^3.0.0", - "lodash._basefor": "^3.0.0", - "lodash.isarray": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basefor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", - "dev": true - }, - "lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash.clonedeep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", - "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", - "dev": true, - "requires": { - "lodash._baseclone": "^3.0.0", - "lodash._bindcallback": "^3.0.0" - } - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", - "dev": true - }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "marked": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", - "dev": true - }, - "marked-terminal": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.3.0.tgz", - "integrity": "sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A==", - "dev": true, - "requires": { - "ansi-escapes": "^3.1.0", - "cardinal": "^2.1.1", - "chalk": "^2.4.1", - "cli-table": "^0.3.1", - "node-emoji": "^1.4.1", - "supports-hyperlinks": "^1.0.1" - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - } - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "metric-lcs": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/metric-lcs/-/metric-lcs-0.1.2.tgz", - "integrity": "sha512-+TZ5dUDPKPJaU/rscTzxyN8ZkX7eAVLAiQU/e+YINleXPv03SCmJShaMT1If1liTH8OcmWXZs0CmzCBRBLcMpA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "dev": true, - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "dev": true, - "optional": true, - "requires": { - "glob": "^6.0.1" - } - } - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "optional": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "nock": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz", - "integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==", - "requires": { - "chai": "^4.1.2", - "debug": "^4.1.0", - "deep-equal": "^1.0.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.5", - "mkdirp": "^0.5.0", - "propagate": "^1.0.0", - "qs": "^6.5.1", - "semver": "^5.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "node-dev": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/node-dev/-/node-dev-3.1.3.tgz", - "integrity": "sha1-WCcZIj69711jBZ5qf7zSOZ/A+E0=", - "dev": true, - "requires": { - "dateformat": "~1.0.4-1.2.3", - "dynamic-dedupe": "^0.2.0", - "filewatcher": "~3.0.0", - "minimist": "^1.1.3", - "node-notifier": "^4.0.2", - "resolve": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "node-notifier": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.1.tgz", - "integrity": "sha1-BW0UJE89zBzq3+aK+c/wxUc6M/M=", - "dev": true, - "requires": { - "cli-usage": "^0.1.1", - "growly": "^1.2.0", - "lodash.clonedeep": "^3.0.0", - "minimist": "^1.1.1", - "semver": "^5.1.0", - "shellwords": "^0.1.0", - "which": "^1.0.5" - } - } - } - }, - "node-emoji": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", - "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", - "dev": true, - "requires": { - "lodash.toarray": "^4.4.0" - } - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node-releases": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.32.tgz", - "integrity": "sha512-VhVknkitq8dqtWoluagsGPn3dxTvN9fwgR59fV3D7sLBHe0JfDramsMI8n8mY//ccq/Kkrf8ZRHRpsyVZ3qw1A==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" - }, - "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-error-resume-next": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-error-resume-next/-/on-error-resume-next-1.1.0.tgz", - "integrity": "sha512-XhWMbmKV0+W95yLJjT1Z9zdkKiPUjDn63YYsji1pdvKqaa7pq4coeHaHEXPsa36SFlffOyOlPK/0rn6Njfb+LA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "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" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "output-file-sync": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", - "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "is-plain-obj": "^1.1.0", - "mkdirp": "^0.5.1" - } - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true, - "optional": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - } - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, - "propagate": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", - "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", - "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" - }, - "react-is": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "dev": true, - "requires": { - "esprima": "~4.0.0" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" - }, - "regenerator-transform": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", - "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", - "dev": true, - "requires": { - "private": "^0.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", - "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", - "requires": { - "define-properties": "^1.1.2" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "dev": true, - "requires": { - "request-promise-core": "1.1.2", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true - }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restify": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/restify/-/restify-5.2.1.tgz", - "integrity": "sha512-OZbqEvRm04Px+vXm3d31sI58HjN2qRaY6O6tA9LGRgyLZJ5+oW4qaLCdKddXfUX6MjtwAc+LLkDQmDbYUifLXA==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "bunyan": "^1.8.1", - "clone-regexp": "^1.0.0", - "csv": "^1.1.0", - "dtrace-provider": "^0.8.1", - "escape-regexp-component": "^1.0.2", - "formidable": "^1.0.17", - "http-signature": "^1.0.0", - "lodash": "^4.17.4", - "lru-cache": "^4.0.1", - "mime": "^1.2.11", - "negotiator": "^0.6.1", - "once": "^1.3.0", - "qs": "^6.2.1", - "restify-errors": "^4.2.3", - "semver": "^5.0.1", - "spdy": "^3.3.3", - "uuid": "^3.0.0", - "vasync": "^1.6.4", - "verror": "^1.9.0" - } - }, - "restify-errors": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-4.3.0.tgz", - "integrity": "sha1-7JDzCTTX8xGRNRgd/DA+ML5gGr4=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "lodash": "^4.2.1", - "safe-json-stringify": "^1.0.3", - "verror": "^1.8.1" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rsa-pem-from-mod-exp": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz", - "integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ=" - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rx": { - "version": "2.3.24", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz", - "integrity": "sha1-FPlQpCF9fjXapxu8vljv9o6ksrc=", - "dev": true - }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "dev": true, - "optional": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "simple-update-in": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/simple-update-in/-/simple-update-in-1.4.0.tgz", - "integrity": "sha512-gb8cWM8KxvF0TbBSFagp0Bw13dk5HBjBVLx8N8pXg4CcVyLiEuu3xxYHLfFEZRn+bYjMCkxjEB8upbWmAVOIyQ==" - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spawn-command": { - "version": "0.0.2-1", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", - "dev": true, - "requires": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", - "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", - "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "spdy-transport": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.1.tgz", - "integrity": "sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==", - "dev": true, - "requires": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", - "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "stream-transform": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.2.2.tgz", - "integrity": "sha1-dYZ0h/SVKPi/HYJJllh1PQLfeDg=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - }, - "dependencies": { - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - } - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-hyperlinks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", - "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", - "dev": true, - "requires": { - "has-flag": "^2.0.0", - "supports-color": "^5.0.0" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - } - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", - "dev": true - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, - "typescript": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.1.tgz", - "integrity": "sha512-Veu0w4dTc/9wlWNf2jeRInNodKlcdLgemvPsrNpfu5Pq39sgfFjvIIgTsvUHCoLBnMhPoUA+tFxsXjU6VexVRQ==", - "dev": true - }, - "typescript-eslint-parser": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-21.0.2.tgz", - "integrity": "sha512-u+pj4RVJBr4eTzj0n5npoXD/oRthvfUCjSKndhNI714MG0mQq2DJw5WP7qmonRNIFgmZuvdDOH3BHm9iOjIAfg==", - "dev": true, - "requires": { - "eslint-scope": "^4.0.0", - "eslint-visitor-keys": "^1.0.0", - "typescript-estree": "5.3.0" - } - }, - "typescript-estree": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/typescript-estree/-/typescript-estree-5.3.0.tgz", - "integrity": "sha512-Vu0KmYdSCkpae+J48wsFC1ti19Hq3Wi/lODUaE+uesc3gzqhWbZ5itWbsjylLVbjNW4K41RqDzSfnaYNbmEiMQ==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } - } - }, - "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "optional": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vasync": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.4.tgz", - "integrity": "sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=", - "dev": true, - "requires": { - "verror": "1.6.0" - }, - "dependencies": { - "extsprintf": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", - "integrity": "sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=", - "dev": true - }, - "verror": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", - "integrity": "sha1-fROyex+swuLakEBetepuW90lLqU=", - "dev": true, - "requires": { - "extsprintf": "1.2.0" - } - } - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xml2js": { - "version": "0.4.22", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", - "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", - "requires": { - "sax": ">=0.6.0", - "util.promisify": "~1.0.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/packages/emulator/core/package.json b/packages/emulator/core/package.json deleted file mode 100644 index e38b40373..000000000 --- a/packages/emulator/core/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "@bfemulator/emulator-core", - "version": "1.0.0-0", - "description": "Local mode server for Bot Framework", - "files": [ - "lib/**/*.js" - ], - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "babel ./src --out-dir lib --extensions \".ts,.tsx\" --ignore \"**/*.spec.ts\" --source-maps inline && tsc --emitDeclarationOnly --declaration", - "build:watch": "npm run build:prod --outdir lib --watch", - "clean": "rimraf lib", - "lint": "eslint --color --quiet --ext .js,.jsx,.ts,.tsx ./src", - "lint:fix": "npm run lint -- --fix", - "start": "node-dev .", - "test": "jest", - "typecheck": "tsc" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/microsoft/botframework-localmode.git" - }, - "keywords": [ - "bot", - "bot framework", - "azure bot services", - "abs", - "local mode" - ], - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/microsoft/botframework-localmode/issues" - }, - "homepage": "https://github.com/microsoft/botframework-localmode#readme", - "jest": { - "transform": { - "^.+\\.(tsx?)$": "babel-jest" - }, - "testURL": "http://localhost", - "rootDir": "./src", - "testMatch": [ - "**/?(*.)(spec|test).(ts)?(x)" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ] - }, - "dependencies": { - "@babel/runtime": "^7.1.5", - "@bfemulator/app-shared": "^1.0.0", - "@bfemulator/sdk-shared": "^1.0.0", - "botframework-connector": "^4.3.4", - "botframework-schema": "^4.3.4", - "debug": "^3.1.0", - "http-status-codes": "^1.3.0", - "jsonwebtoken": "^8.3.0", - "moment": "^2.22.1", - "node-fetch": "^2.3.0", - "npmlog": "^4.1.2", - "on-error-resume-next": "^1.0.0", - "rsa-pem-from-mod-exp": "^0.8.4", - "simple-update-in": "^1.1.1", - "uuid": "^3.3.2" - }, - "devDependencies": { - "@babel/cli": "^7.1.0", - "@babel/core": "^7.1.0", - "@babel/plugin-proposal-class-properties": "^7.1.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-runtime": "^7.4.4", - "@babel/preset-env": "^7.1.0", - "@babel/preset-typescript": "^7.1.0", - "@types/jest": "24.0.13", - "@types/node": "8.9.3", - "@types/restify": "^5.0.7", - "babel-core": "^7.0.0-bridge.0", - "babel-jest": "24.8.0", - "base64url": "3.0.0", - "concurrently": "^3.5.1", - "eslint": "^5.12.0", - "eslint-config-prettier": "^3.5.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-notice": "^0.7.7", - "eslint-plugin-prettier": "^3.0.1", - "eslint-plugin-typescript": "^1.0.0-rc.3", - "extend": "~3.0.1", - "jest": "24.8.0", - "node-dev": "^3.1.3", - "restify": "^5.0.0", - "rimraf": "^2.6.2", - "typescript": "3.1.1" - } -} diff --git a/packages/emulator/core/src/attachments/middleware/attachmentsMiddleware.spec.ts b/packages/emulator/core/src/attachments/middleware/attachmentsMiddleware.spec.ts deleted file mode 100644 index e3b0bcacd..000000000 --- a/packages/emulator/core/src/attachments/middleware/attachmentsMiddleware.spec.ts +++ /dev/null @@ -1,209 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -import * as HttpStatus from 'http-status-codes'; - -import Attachments from '../../facility/attachments'; - -import getAttachment from './getAttachment'; -import getAttachmentInfo from './getAttachmentInfo'; - -describe('The getAttachment middleware', () => { - let facilities; - let attachments; - let attachmentId; - const mockAttachmentData = new Uint8Array(Buffer.from('aGk=')); - - beforeEach(() => { - attachments = new Attachments(); - attachmentId = attachments.uploadAttachment({ - name: 'an attachment', - originalBase64: mockAttachmentData, - type: 'application/text', - thumbnailBase64: mockAttachmentData, - }); - facilities = { - attachments, - }; - }); - - it('should get the specified attachment', () => { - const getAttachmentMiddleware = getAttachment({ facilities } as any); - - const req = { - params: { - viewId: 'thumbnail', - attachmentId, - }, - }; - - const res = { - send: () => null, - end: () => void 0, - contentType: '', - }; - - const sendSpy = jest.spyOn(res, 'send'); - - getAttachmentMiddleware( - req as any, - res as any, - function() { - return null; - } as any - ); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, Buffer.from(mockAttachmentData)); - expect(res.contentType).toBe('application/text'); - }); - - it('should send an error response when the "originalBase64" and "thumbnailBase64" are falsy', () => { - const getAttachmentMiddleware = getAttachment({ facilities } as any); - (attachments as any).attachments[attachmentId].originalBase64 = undefined; - (attachments as any).attachments[attachmentId].thumbnailBase64 = undefined; - const req = { - params: { - viewId: 'thumbnail', - attachmentId, - }, - }; - - const res = { - send: () => null, - end: () => null, - contentType: '', - }; - - const sendSpy = jest.spyOn(res, 'send'); - - getAttachmentMiddleware( - req as any, - res as any, - function() { - return null; - } as any - ); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, { - error: { - code: 'BadArgument', - message: 'There is no thumbnail view', - }, - }); - expect(res.contentType).toBe(''); - }); -}); - -describe('the getAttachmentInfo middleware', () => { - let facilities; - let attachments; - let attachmentId; - beforeEach(() => { - attachments = new Attachments(); - attachmentId = attachments.uploadAttachment({ - name: 'an attachment', - originalBase64: new Uint8Array(Buffer.from('aGk=')), - type: 'application/text', - thumbnailBase64: new Uint8Array(Buffer.from('aGk=')), - }); - facilities = { - attachments, - }; - }); - - it('should get the attachment info when a valid request is made', () => { - const getAttachmentInfoMiddleware = getAttachmentInfo({ - facilities, - } as any); - const req = { - params: { - viewId: 'thumbnail', - attachmentId, - }, - }; - - const res = { - send: () => null, - end: () => null, - contentType: '', - }; - const sendSpy = jest.spyOn(res, 'send'); - - getAttachmentInfoMiddleware( - req as any, - res as any, - function() { - return null; - } as any - ); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - name: 'an attachment', - type: 'application/text', - views: [{ size: 2, viewId: 'original' }, { size: 2, viewId: 'thumbnail' }], - }); - }); - - it('should send an error response when the attachment is not found', () => { - const getAttachmentInfoMiddleware = getAttachmentInfo({ - facilities, - } as any); - const req = { - params: { - viewId: 'thumbnail', - attachmentId: 'not there', - }, - }; - - const res = { - send: () => null, - end: () => null, - contentType: '', - }; - const sendSpy = jest.spyOn(res, 'send'); - - getAttachmentInfoMiddleware( - req as any, - res as any, - function() { - return null; - } as any - ); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.NOT_FOUND, { - error: { - code: 'BadArgument', - message: 'attachment[not there] not found', - }, - }); - }); -}); diff --git a/packages/emulator/core/src/attachments/registerRoutes.spec.ts b/packages/emulator/core/src/attachments/registerRoutes.spec.ts deleted file mode 100644 index 4deb04b9d..000000000 --- a/packages/emulator/core/src/attachments/registerRoutes.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; - -import registerRoutes from './registerRoutes'; -import getAttachment from './middleware/getAttachment'; -import getAttachmentInfo from './middleware/getAttachmentInfo'; - -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('./middleware/getAttachment', () => jest.fn(() => null)); -jest.mock('./middleware/getAttachmentInfo', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const server: any = { - get, - }; - const uses = []; - const emulator: any = {}; - registerRoutes(emulator, server, uses); - - expect(getFacility).toHaveBeenCalledWith('attachments'); - expect(get).toHaveBeenCalledWith( - '/v3/attachments/:attachmentId', - ...uses, - getFacility('attachments'), - getRouteName('getAttachmentInfo'), - getAttachmentInfo(emulator) - ); - expect(get).toHaveBeenCalledWith( - '/v3/attachments/:attachmentId/views/:viewId', - ...uses, - getFacility('attachments'), - getRouteName('getAttachment'), - getAttachment(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/botEmulator.spec.ts b/packages/emulator/core/src/botEmulator.spec.ts deleted file mode 100644 index 073937c8b..000000000 --- a/packages/emulator/core/src/botEmulator.spec.ts +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { GenericActivity, ILogItem } from '@bfemulator/sdk-shared'; - -import { BotEmulator } from './botEmulator'; -import ConsoleLogService from './facility/consoleLogService'; -import registerAttachmentRoutes from './attachments/registerRoutes'; -import registerBotStateRoutes from './botState/registerRoutes'; -import registerConversationRoutes from './conversations/registerRoutes'; -import registerDirectLineRoutes from './directLine/registerRoutes'; -import registerEmulatorRoutes from './emulator/registerRoutes'; -import registerSessionRoutes from './session/registerRoutes'; -import registerUserTokenRoutes from './userToken/registerRoutes'; -import stripEmptyBearerToken from './utils/stripEmptyBearerToken'; - -jest.mock('./attachments/registerRoutes', () => jest.fn(() => null)); -jest.mock('./botState/registerRoutes', () => jest.fn(() => null)); -jest.mock('./conversations/registerRoutes', () => jest.fn(() => null)); -jest.mock('./directLine/registerRoutes', () => jest.fn(() => null)); -jest.mock('./emulator/registerRoutes', () => jest.fn(() => null)); -jest.mock('./session/registerRoutes', () => jest.fn(() => null)); -jest.mock('./userToken/registerRoutes', () => jest.fn(() => null)); -jest.mock('./utils/stripEmptyBearerToken', () => jest.fn(() => null)); - -const mockAcceptParser = jest.fn(_acceptable => null); -const mockDateParser = jest.fn(() => null); -const mockQueryParser = jest.fn(() => null); -jest.mock('restify', () => ({ - plugins: { - get acceptParser() { - return mockAcceptParser; - }, - get dateParser() { - return mockDateParser; - }, - get queryParser() { - return mockQueryParser; - }, - }, -})); - -describe('BotEmulator', () => { - it('should instantiate itself properly', async () => { - const getServiceUrl = _url => Promise.resolve('serviceUrl'); - const getServiceUrlForOAuth = () => Promise.resolve('serviceUrlForOAuth'); - const shutDownOAuthNgrokInstance = jest.fn(() => null); - const customFetch = (_url, _options) => Promise.resolve(); - const customLogger = { - logActivity: (_conversationId: string, _activity: GenericActivity, _role: string) => 'activityLogged', - logMessage: (_conversationId: string, ..._items: ILogItem[]) => 'messageLogged', - logException: (_conversationId: string, _err: Error) => 'exceptionLogged', - }; - const customLogService = new ConsoleLogService(); - - // with logger - const options1 = { - fetch: customFetch, - loggerOrLogService: customLogger, - }; - const botEmulator1 = new BotEmulator(getServiceUrl, getServiceUrlForOAuth, shutDownOAuthNgrokInstance, options1); - const serviceUrl = await botEmulator1.getServiceUrl(''); - const serviceUrlForOAuth = await botEmulator1.getServiceUrlForOAuth(); - botEmulator1.shutDownOAuthNgrokInstance(); - - expect(serviceUrl).toBe('serviceUrl'); - expect(serviceUrlForOAuth).toBe('serviceUrlForOAuth'); - expect(shutDownOAuthNgrokInstance).toHaveBeenCalled(); - expect(botEmulator1.options).toEqual({ ...options1, stateSizeLimitKB: 64 }); - expect(botEmulator1.facilities.attachments).not.toBeFalsy(); - expect(botEmulator1.facilities.botState).not.toBeFalsy(); - expect(botEmulator1.facilities.conversations).not.toBeFalsy(); - expect(botEmulator1.facilities.endpoints).not.toBeFalsy(); - expect(botEmulator1.facilities.logger).not.toBeFalsy(); - expect(botEmulator1.facilities.users).not.toBeFalsy(); - expect(botEmulator1.facilities.botState.stateSizeLimitKB).toBe(64); - expect(await botEmulator1.facilities.logger.logActivity('', null, '')).toBe('activityLogged'); - expect(await botEmulator1.facilities.logger.logException('', null)).toBe('exceptionLogged'); - expect(await botEmulator1.facilities.logger.logMessage('')).toBe('messageLogged'); - - // with log service - const options2 = { - fetch: customFetch, - loggerOrLogService: customLogService, - }; - const botEmulator2 = new BotEmulator(getServiceUrl, options2); - - expect((botEmulator2.facilities.logger as any).logService).toEqual(customLogService); - }); - - it('should mount routes onto a restify server', () => { - const getServiceUrl = _url => Promise.resolve('serviceUrl'); - const botEmulator = new BotEmulator(getServiceUrl); - const restifyServer = { acceptable: true }; - const mockUses = [ - mockAcceptParser(restifyServer.acceptable), - stripEmptyBearerToken(), - mockDateParser(), - mockQueryParser(), - ]; - mockAcceptParser.mockClear(); - (stripEmptyBearerToken as any).mockClear(); - mockDateParser.mockClear(); - mockQueryParser.mockClear(); - - const mountedEmulator = botEmulator.mount(restifyServer as any); - - expect(mountedEmulator).toEqual(botEmulator); - expect(mockAcceptParser).toHaveBeenCalledWith(restifyServer.acceptable); - expect(stripEmptyBearerToken).toHaveBeenCalled(); - expect(mockDateParser).toHaveBeenCalled(); - expect(mockQueryParser).toHaveBeenCalled(); - expect(registerAttachmentRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerBotStateRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerConversationRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerDirectLineRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerSessionRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerUserTokenRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - expect(registerEmulatorRoutes).toHaveBeenCalledWith(botEmulator, restifyServer, mockUses); - }); -}); diff --git a/packages/emulator/core/src/botEmulator.ts b/packages/emulator/core/src/botEmulator.ts deleted file mode 100644 index 063eb933b..000000000 --- a/packages/emulator/core/src/botEmulator.ts +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { BotEmulatorOptions, Logger, LogService } from '@bfemulator/sdk-shared'; -import * as Restify from 'restify'; -import fetch from 'node-fetch'; - -import registerAttachmentRoutes from './attachments/registerRoutes'; -import registerBotStateRoutes from './botState/registerRoutes'; -import registerConversationRoutes from './conversations/registerRoutes'; -import registerDirectLineRoutes from './directLine/registerRoutes'; -import registerEmulatorRoutes from './emulator/registerRoutes'; -import Attachments from './facility/attachments'; -import BotState from './facility/botState'; -import ConsoleLogService from './facility/consoleLogService'; -import ConversationSet from './facility/conversationSet'; -import EndpointSet from './facility/endpointSet'; -import LoggerAdapter from './facility/loggerAdapter'; -import Users from './facility/users'; -import registerSessionRoutes from './session/registerRoutes'; -import registerUserTokenRoutes from './userToken/registerRoutes'; -import stripEmptyBearerToken from './utils/stripEmptyBearerToken'; - -const DEFAULT_OPTIONS: BotEmulatorOptions = { - fetch, - loggerOrLogService: new ConsoleLogService(), - stateSizeLimitKB: 64, -}; - -export interface Facilities { - attachments: Attachments; - botState: BotState; - conversations: ConversationSet; - endpoints: EndpointSet; - logger: Logger; - users: Users; - locale?: string; -} - -export class BotEmulator { - // TODO: Instead of providing a getter for serviceUrl, we should let the upstream to set the serviceUrl - // Currently, the upstreamer doesn't really know when the serviceUrl change (ngrok), they need to do their job - public getServiceUrl: (botUrl: string) => Promise; - public getServiceUrlForOAuth: () => Promise; - public shutDownOAuthNgrokInstance: () => void; - public options: BotEmulatorOptions; - public facilities: Facilities; - - constructor( - getServiceUrl: (botUrl: string) => Promise, - getServiceUrlForOAuth: () => Promise, - shutDownOAuthNgrokInstance: () => void, - options: BotEmulatorOptions = DEFAULT_OPTIONS - ) { - this.getServiceUrl = getServiceUrl; - this.getServiceUrlForOAuth = getServiceUrlForOAuth; - this.shutDownOAuthNgrokInstance = shutDownOAuthNgrokInstance; - - this.options = { ...DEFAULT_OPTIONS, ...options }; - - const logService = this.options.loggerOrLogService as LogService; - const logger: Logger = - logService && logService.logToChat - ? new LoggerAdapter(logService as LogService) - : (this.options.loggerOrLogService as Logger); - - this.facilities = { - attachments: new Attachments(), - botState: new BotState(this, this.options.stateSizeLimitKB), - conversations: new ConversationSet(), - endpoints: new EndpointSet(this.options), - logger, - users: new Users(), - }; - } - - public mount(router: Restify.Server): BotEmulator { - const uses = [ - Restify.plugins.acceptParser(router.acceptable), - stripEmptyBearerToken(), - Restify.plugins.dateParser(), - Restify.plugins.queryParser(), - ]; - - registerAttachmentRoutes(this, router, uses); - registerBotStateRoutes(this, router, uses); - registerConversationRoutes(this, router, uses); - registerDirectLineRoutes(this, router, uses); - registerSessionRoutes(this, router, uses); - registerUserTokenRoutes(this, router, uses); - registerEmulatorRoutes(this, router, uses); - - return this; - } -} diff --git a/packages/emulator/core/src/botState/middleware/botstateMiddleware.spec.ts b/packages/emulator/core/src/botState/middleware/botstateMiddleware.spec.ts deleted file mode 100644 index 2ec601f5d..000000000 --- a/packages/emulator/core/src/botState/middleware/botstateMiddleware.spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -import { User } from '@bfemulator/sdk-shared'; -import * as HttpStatus from 'http-status-codes'; - -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import BotState from '../../facility/botState'; -import Conversation from '../../facility/conversation'; -import ConversationSet from '../../facility/conversationSet'; - -import deleteStateForUser from './deleteStateForUser'; -import fetchBotData from './fetchBotData'; -import getConversationData from './getConversationData'; -import getPrivateConversationData from './getPrivateConversationData'; -import getUserData from './getUserData'; -import setConversationData from './setConversationData'; -import setPrivateConversationData from './setPrivateConversationData'; - -describe('The botStateMiddleware', () => { - let botState: BotState; - let emulator: BotEmulator; - let conversation: Conversation; - let user: User; - let res; - const channelId = '3c'; - beforeEach(() => { - res = { - send: () => null, - end: () => null, - contentType: '', - }; - - emulator = { facilities: { logger: { logMessage: () => true } } } as any; - emulator.facilities.conversations = new ConversationSet(); - user = { id: '321', name: 'a user' }; - const endpoint = new BotEndpoint('12', '123', 'http://localhost:12345', '', '', false, '', {}); - conversation = emulator.facilities.conversations.newConversation(emulator, endpoint, user); - botState = new BotState(emulator, 256); - jest.spyOn(Date, 'now').mockReturnValue({ toString: () => '123456' }); - botState.setBotData(channelId, conversation.conversationId, user.id, { - eTag: '', - data: { state: 'none' }, - }); - emulator.facilities.botState = botState; - }); - - it('should delete the state for the user', () => { - const deleteStateMiddleware = deleteStateForUser(emulator); - - const req = { - params: { userId: user.id }, - accepts: 'application/json', - acceptsEncoding: 'utf8', - }; - - const sendSpy = jest.spyOn(res, 'send'); - deleteStateMiddleware(req as any, res as any, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK); - expect(emulator.facilities.botState.getBotData(channelId, conversation.conversationId, user.id)).toEqual({ - data: null, - eTag: '*', - }); - }); - - it('should fetch the specified bot data', () => { - const fetchBotDataMiddleware = fetchBotData(emulator); - const req = { - params: { - userId: user.id, - conversationId: conversation.conversationId, - channelId, - }, - botData: null, - }; - fetchBotDataMiddleware(req as any, res, (() => null) as any); - expect(req.botData).toEqual({ data: { state: 'none' }, eTag: '123456' }); - }); - - it('should get the conversation data', () => { - const getConversationDataMiddleware = getConversationData(emulator); - const req = { - botData: { testBotData: true }, - }; - const sendSpy = jest.spyOn(res, 'send'); - getConversationDataMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, req.botData); - }); - - it('should get private conversation data', () => { - const privateConversationMiddleware = getPrivateConversationData(emulator); - const req = { - botData: { testBotData: true }, - }; - const sendSpy = jest.spyOn(res, 'send'); - privateConversationMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, req.botData); - }); - - it('should get the user data', () => { - const getUserDataMiddleware = getUserData(emulator); - const req = { - botData: { testBotData: true }, - }; - const sendSpy = jest.spyOn(res, 'send'); - getUserDataMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, req.botData); - }); - - it('should set conversation data', () => { - const setConversationMiddleware = setConversationData(emulator); - const req = { - params: { - channelId, - conversationId: conversation.conversationId, - userId: '321', - }, - body: { data: { newBotData: true }, eTag: '123456' }, - }; - const sendSpy = jest.spyOn(res, 'send'); - setConversationMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - data: req.body.data, - eTag: '123456', - }); - expect(emulator.facilities.botState.getBotData(channelId, conversation.conversationId, user.id)).toEqual({ - data: { newBotData: true }, - eTag: '123456', - }); - }); - - it('should set private conversation data', () => { - const setPrivateConversationDataMiddleware = setPrivateConversationData(emulator); - const req = { - params: { - channelId, - conversationId: conversation.conversationId, - userId: '321', - }, - body: { data: { newBotData: true }, eTag: '123456' }, - }; - const sendSpy = jest.spyOn(res, 'send'); - setPrivateConversationDataMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - data: req.body.data, - eTag: '123456', - }); - expect(emulator.facilities.botState.getBotData(channelId, conversation.conversationId, user.id)).toEqual({ - data: { newBotData: true }, - eTag: '123456', - }); - }); - - it('should set the user data', () => { - const setUserDataMiddleware = setPrivateConversationData(emulator); - const req = { - params: { - channelId, - conversationId: conversation.conversationId, - userId: '321', - }, - body: { data: { newBotData: true }, eTag: '123456' }, - }; - const sendSpy = jest.spyOn(res, 'send'); - setUserDataMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - data: req.body.data, - eTag: '123456', - }); - expect(emulator.facilities.botState.getBotData(channelId, conversation.conversationId, user.id)).toEqual({ - data: { newBotData: true }, - eTag: '123456', - }); - }); -}); diff --git a/packages/emulator/core/src/botState/middleware/setUserData.ts b/packages/emulator/core/src/botState/middleware/setUserData.ts deleted file mode 100644 index af23ef0d0..000000000 --- a/packages/emulator/core/src/botState/middleware/setUserData.ts +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { BotData } from '@bfemulator/sdk-shared'; -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -export default function setUserData(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const botData = botEmulator.facilities.botState.setBotData( - req.params.channelId, - req.params.conversationId, - req.params.userId, - req.body as BotData - ); - - res.send(HttpStatus.OK, botData); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - - next(); - }; -} diff --git a/packages/emulator/core/src/botState/registerRoutes.spec.ts b/packages/emulator/core/src/botState/registerRoutes.spec.ts deleted file mode 100644 index 9dd091986..000000000 --- a/packages/emulator/core/src/botState/registerRoutes.spec.ts +++ /dev/null @@ -1,150 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import jsonBodyParser from '../utils/jsonBodyParser'; - -import registerRoutes from './registerRoutes'; -import deleteStateForUser from './middleware/deleteStateForUser'; -import createFetchBotDataMiddleware from './middleware/fetchBotData'; -import getConversationData from './middleware/getConversationData'; -import getPrivateConversationData from './middleware/getPrivateConversationData'; -import getUserData from './middleware/getUserData'; -import setConversationData from './middleware/setConversationData'; -import setPrivateConversationData from './middleware/setPrivateConversationData'; -import setUserData from './middleware/setUserData'; - -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('../utils/botFrameworkAuthentication', () => jest.fn(() => null)); -jest.mock('../utils/jsonBodyParser', () => jest.fn(() => null)); -jest.mock('./middleware/deleteStateForUser', () => jest.fn(() => null)); -jest.mock('./middleware/fetchBotData', () => jest.fn(() => null)); -jest.mock('./middleware/getConversationData', () => jest.fn(() => null)); -jest.mock('./middleware/getPrivateConversationData', () => jest.fn(() => null)); -jest.mock('./middleware/getUserData', () => jest.fn(() => null)); -jest.mock('./middleware/setConversationData', () => jest.fn(() => null)); -jest.mock('./middleware/setPrivateConversationData', () => jest.fn(() => null)); -jest.mock('./middleware/setUserData', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const post = jest.fn(() => null); - const del = jest.fn(() => null); - const server: any = { - get, - post, - del, - }; - const uses = []; - const emulator: any = { - options: { fetch: () => null }, - }; - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulator.options.fetch); - const fetchBotDataMiddleware = createFetchBotDataMiddleware(emulator); - const facility = getFacility('state'); - registerRoutes(emulator, server, uses); - - expect(get).toHaveBeenCalledWith( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getUserData'), - getUserData(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/botstate/:channelId/conversations/:conversationId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getConversationData'), - getConversationData(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/botstate/:channelId/conversations/:conversationId/users/:userId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getPrivateConversationData'), - getPrivateConversationData(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setUserData'), - setUserData(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/botstate/:channelId/conversations/:conversationId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setConversationData'), - setConversationData(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/botstate/:channelId/conversations/:conversationId/users/:userId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setPrivateConversationData'), - setPrivateConversationData(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - facility, - getRouteName('deleteStateForUser'), - deleteStateForUser(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/botState/registerRoutes.ts b/packages/emulator/core/src/botState/registerRoutes.ts deleted file mode 100644 index 0d6087ae7..000000000 --- a/packages/emulator/core/src/botState/registerRoutes.ts +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import jsonBodyParser from '../utils/jsonBodyParser'; - -import deleteStateForUser from './middleware/deleteStateForUser'; -import createFetchBotDataMiddleware from './middleware/fetchBotData'; -import getConversationData from './middleware/getConversationData'; -import getPrivateConversationData from './middleware/getPrivateConversationData'; -import getUserData from './middleware/getUserData'; -import setConversationData from './middleware/setConversationData'; -import setPrivateConversationData from './middleware/setPrivateConversationData'; -import setUserData from './middleware/setUserData'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - // TODO: Check if it works without MSA App ID - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(botEmulator.options.fetch); - // const verifyBotFramework = botEmulator.msaAppId ? - // createBotFrameworkAuthenticationMiddleware(botEmulator.botId, botEmulator.options.fetch) : []; - const fetchBotDataMiddleware = createFetchBotDataMiddleware(botEmulator); - const facility = getFacility('state'); - - server.get( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getUserData'), - getUserData(botEmulator) - ); - - server.get( - '/v3/botstate/:channelId/conversations/:conversationId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getConversationData'), - getConversationData(botEmulator) - ); - - server.get( - '/v3/botstate/:channelId/conversations/:conversationId/users/:userId', - ...uses, - verifyBotFramework, - fetchBotDataMiddleware, - facility, - getRouteName('getPrivateConversationData'), - getPrivateConversationData(botEmulator) - ); - - server.post( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setUserData'), - setUserData(botEmulator) - ); - - server.post( - '/v3/botstate/:channelId/conversations/:conversationId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setConversationData'), - setConversationData(botEmulator) - ); - - server.post( - '/v3/botstate/:channelId/conversations/:conversationId/users/:userId', - ...uses, - verifyBotFramework, - jsonBodyParser(), - facility, - getRouteName('setPrivateConversationData'), - setPrivateConversationData(botEmulator) - ); - - server.del( - '/v3/botstate/:channelId/users/:userId', - ...uses, - verifyBotFramework, - facility, - getRouteName('deleteStateForUser'), - deleteStateForUser(botEmulator) - ); -} diff --git a/packages/emulator/core/src/conversations/middleware/conversationsMiddleware.spec.ts b/packages/emulator/core/src/conversations/middleware/conversationsMiddleware.spec.ts deleted file mode 100644 index 372c9f635..000000000 --- a/packages/emulator/core/src/conversations/middleware/conversationsMiddleware.spec.ts +++ /dev/null @@ -1,709 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -import { AttachmentData } from '@bfemulator/sdk-shared'; -import { ConversationParameters, Activity } from 'botframework-schema'; -import * as HttpStatus from 'http-status-codes'; - -import { BotEmulator } from '../../botEmulator'; -import { usGovernmentAuthentication } from '../../authEndpoints'; -import Attachments from '../../facility/attachments'; -import BotEndpoint from '../../facility/botEndpoint'; -import Conversation from '../../facility/conversation'; -import ConversationSet from '../../facility/conversationSet'; -import Endpoints from '../../facility/endpointSet'; -import Users from '../../facility/users'; - -import createConversation from './createConversation'; -import deleteActivity from './deleteActivity'; -import fetchConversation from './fetchConversation'; -import getActivityMembers from './getActivityMembers'; -import getBotEndpoint from './getBotEndpoint'; -import replyToActivity from './replyToActivity'; -import sendActivityToConversation from './sendActivityToConversation'; -import sendHistoryToConversation from './sendHistoryToConversation'; -import updateActivity from './updateActivity'; -import uploadAttachment from './uploadAttachment'; -import createFetchConversationMiddleware from './getConversations'; - -describe('The conversations middleware', () => { - let emulator: BotEmulator; - let res; - beforeEach(() => { - res = { - send: () => null, - end: () => null, - contentType: '', - }; - emulator = createEmulatorUtil(); - }); - - it('should create a new conversation', () => { - const bot = { role: 'bot', name: 'thebot', id: '456' }; - const req = { - botEndpoint: new BotEndpoint('12', '456', 'http://localhost:12345', '', '', false, '', {}), - body: { - isGroup: false, - members: [{ id: '456', name: 'emulator', role: 'user' }], - bot, - conversationId: '007', - activity: null, - channelData: null, - } as ConversationParameters, - }; - // Bind to an object with a botId property. - // TODO - determine if this is a potential defect. - const createConversationMiddleware = createConversation.bind({ - botId: bot.id, - })(emulator); - const sendSpy = jest.spyOn(res, 'send'); - createConversationMiddleware(req as any, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: '007|livechat', - }); - - const newConversation = emulator.facilities.conversations.conversationById('007|livechat'); - expect(newConversation).toBeTruthy(); - expect(newConversation.botEndpoint).toEqual(req.botEndpoint); - expect(newConversation.user).toEqual({ id: '456', name: 'emulator' }); - expect(newConversation.members).toEqual([{ id: '456', name: 'Bot' }, { id: '456', name: 'emulator' }]); - }); - - it('should delete an activity', () => { - // create the conversation with an activity - const bot = { role: 'bot', name: 'thebot', id: '456' }; - let req: any = { - botEndpoint: new BotEndpoint('12', '456', 'http://localhost:12345', '', '', false, '', {}), - body: { - isGroup: false, - members: [{ id: '456', name: 'emulator', role: 'user' }], - bot, - conversationId: '007', - activity: {} as Activity, - channelData: null, - } as ConversationParameters, - }; - const createConversationMiddleware = createConversation.bind({ - botId: bot.id, - })(emulator); - let activity = { activityId: '' }; - res.send = (_, actvty) => (activity = actvty); - createConversationMiddleware(req as any, res, (() => null) as any); - const conversation = emulator.facilities.conversations.conversationById('007|livechat'); - req = { - params: { - activityId: activity.activityId, - }, - conversation, - }; - expect((conversation as any).activities.length).toBe(1); - const deleteActivityMiddleware = deleteActivity(emulator); - const sendSpy = jest.spyOn(res, 'send'); - deleteActivityMiddleware(req, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK); - expect((conversation as any).activities.length).toBeFalsy(); - }); - - it('should fetch a conversation', () => { - const targetConversation = createConversationUtil(emulator); - - const req = { - params: { - conversationId: '007|livechat', - }, - conversation: null, - }; - - const fetchConversationMiddleware = fetchConversation(emulator); - fetchConversationMiddleware(req as any, res, (() => null) as any); - expect(req.conversation).toBe(targetConversation); - }); - - it('should get activity members', () => { - const conversation = createConversationUtil(emulator); - - const getActivityMembersMiddleware = getActivityMembers(emulator); - const sendSpy = jest.spyOn(res, 'send'); - const req = { - conversation, - }; - - getActivityMembersMiddleware(req as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, conversation.members); - }); - - it('should reply to an activity', async () => { - const conversation = createConversationUtil(emulator); - const mockActivity = { - conversation: { - id: '007', - }, - id: '1', - recipient: { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - from: { - id: 'vY4U6Daqs1rrWK5uIDlp8eFHHq0=', - }, - timestamp: '2018-08-28T16:34:49.100Z', - type: 'conversationUpdate', - channelId: 'chatdown', - membersAdded: [ - { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - ], - membersRemoved: [], - }; - const replyToActivityMiddleware = replyToActivity(emulator); - const req = { - conversation, - body: mockActivity, - params: { - activityId: '456', - }, - headers: { - authorization: Buffer.from('authtoken').toString('base64'), - }, - }; - const sendSpy = jest.spyOn(res, 'send'); - await replyToActivityMiddleware(req as any, res, (() => null) as any); - const { activities } = conversation.getActivitiesSince(0); - expect(activities.length).toBe(2); - expect(activities[1].replyToId).toBe('456'); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: activities[1].id, - }); - }); - - it('should send an activity to the conversation', () => { - const conversation = createConversationUtil(emulator); - const mockActivity = { - conversation: { - id: '007', - }, - id: '1', - recipient: { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - from: { - id: 'vY4U6Daqs1rrWK5uIDlp8eFHHq0=', - }, - timestamp: '2018-08-28T16:34:49.100Z', - type: 'conversationUpdate', - channelId: 'chatdown', - membersAdded: [ - { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - ], - membersRemoved: [], - }; - const req = { - conversation, - body: mockActivity, - params: { - activityId: '1234', - }, - }; - const sendActivityMiddleware = sendActivityToConversation(emulator); - const sendSpy = jest.spyOn(res, 'send'); - sendActivityMiddleware(req as any, res, (() => null) as any); - const { activities } = conversation.getActivitiesSince(0); - expect(activities.length).toBe(2); - expect(activities[1].replyToId).toBe('1234'); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: activities[1].id, - }); - }); - - it('should send history to the conversation', () => { - const mockActivities = [ - { - type: 'conversationUpdate', - membersAdded: [ - { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - }, - ], - channelId: 'emulator', - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - id: '6e9e1e00-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:08-07:00', - recipient: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - timestamp: '2018-09-20T15:47:08.895Z', - from: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - name: 'User', - }, - serviceUrl: 'https://a457e760.ngrok.io', - }, - { - type: 'conversationUpdate', - membersAdded: [ - { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - name: 'User', - }, - ], - channelId: 'emulator', - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - id: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:08-07:00', - recipient: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - timestamp: '2018-09-20T15:47:08.907Z', - from: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - name: 'User', - }, - serviceUrl: 'https://a457e760.ngrok.io', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - text: 'Hello, I am the Contoso Cafe Bot!', - inputHint: 'acceptingInput', - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6edf1ea0-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:09-07:00', - timestamp: '2018-09-20T15:47:09.322Z', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - text: 'I can help book a table, find cafe locations and more..', - inputHint: 'acceptingInput', - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6f141151-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:09-07:00', - timestamp: '2018-09-20T15:47:09.669Z', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - attachments: [ - { - contentType: 'application/vnd.microsoft.card.adaptive', - content: { - type: 'AdaptiveCard', - horizontalAlignment: 'Center', - separator: true, - height: 'stretch', - body: [ - { - type: 'ColumnSet', - horizontalAlignment: 'Center', - spacing: 'large', - height: 'stretch', - columns: [ - { - type: 'Column', - spacing: 'large', - items: [ - { - type: 'TextBlock', - size: 'extraLarge', - weight: 'bolder', - text: 'Contoso Cafe', - }, - { - type: 'TextBlock', - size: 'Medium', - text: "Hello, I'm the Cafe bot! How can I be of help today?", - wrap: true, - }, - ], - }, - { - type: 'Column', - spacing: 'small', - items: [ - { - type: 'Image', - horizontalAlignment: 'center', - url: 'http://contosocafeontheweb.azurewebsites.net/assets/contoso_logo_black.png', - size: 'medium', - }, - ], - width: 'auto', - }, - ], - }, - ], - actions: [ - { - type: 'Action.Submit', - title: 'Book table', - data: { - intent: 'Book_Table', - }, - }, - { - type: 'Action.Submit', - title: 'What can you do?', - data: { - intent: 'What_can_you_do', - }, - }, - ], - $schema: 'http://adaptivecards.io/schemas/adaptive-card.json', - version: '1.0', - }, - }, - ], - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6f47f290-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:10-07:00', - timestamp: '2018-09-20T15:47:10.009Z', - }, - ]; - const conversation = createConversationUtil(emulator); - const req = { - conversation, - body: { activities: mockActivities }, - }; - const sendHistoryToConversationMiddleware = sendHistoryToConversation(emulator); - const sendSpy = jest.spyOn(res, 'send'); - sendHistoryToConversationMiddleware(req as any, res, (() => null) as any); - const { activities } = conversation.getActivitiesSince(1); - expect(activities.length).toBe(5); - activities.forEach((activity, index) => { - expect(activity).toEqual({ - ...mockActivities[index], - localTimestamp: jasmine.any(String), - }); - }); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: jasmine.any(String), - }); - }); - - it('should update an activity', () => { - const mockActivity = { - conversation: { - id: '007', - }, - id: '1234', - recipient: { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - from: { - id: 'vY4U6Daqs1rrWK5uIDlp8eFHHq0=', - }, - attachments: [], - timestamp: '2018-08-28T16:34:49.100Z', - type: 'conversationUpdate', - channelId: 'chatdown', - membersAdded: [ - { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - ], - membersRemoved: [], - }; - const conversation = createConversationUtil(emulator); - const req = { - conversation, - body: mockActivity as any, - params: { - activityId: mockActivity.id, - }, - }; - sendActivityToConversation(emulator)(req as any, res, (() => null) as any); - const { activities } = conversation.getActivitiesSince(0); - const [activity] = activities; - const updateActivityMiddleware = updateActivity(emulator); - req.body = { - ...req.body, - text: 'Hi there!', - id: activity.id, - } as Activity; - req.params.activityId = activity.id; - - const sendSpy = jest.spyOn(res, 'send'); - updateActivityMiddleware(req as any, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: jasmine.any(String), - }); - expect((conversation.getActivitiesSince(0).activities[0] as Activity).text).toBe('Hi there!'); - }); - - it('should upload an attachment', () => { - const mockAttachment = { - type: 'application/json', - originalBase64: Buffer.from('{}').toString('base64'), - } as AttachmentData; - - const uploadAttachmentMiddleware = uploadAttachment(emulator); - const req = { - body: mockAttachment, - }; - - const sendSpy = jest.spyOn(res, 'send'); - uploadAttachmentMiddleware(req as any, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { - id: jasmine.any(String), - }); - expect(Object.keys((emulator.facilities.attachments as any).attachments).length).toBe(1); - }); -}); - -describe('The getBotEndpoint middleware', () => { - let emulator: BotEmulator; - let res; - let getBotEndpointMiddleware; - let sentResponses; - beforeEach(() => { - sentResponses = []; - res = { - send: (...args) => sentResponses.push(args), - end: () => null, - contentType: '', - }; - emulator = createEmulatorUtil(); - getBotEndpointMiddleware = getBotEndpoint(emulator); - }); - - it('should push a new endpoint to the EndpointSet when the params contain the appropriate data', () => { - const req = { - body: { - bot: { - id: '1234', - }, - }, - headers: { - 'x-emulator-botendpoint': 'http://localhost:5050/api/messages', - 'x-emulator-appid': '12e34', - 'x-emulator-apppassword': '54543', - }, - } as any; - getBotEndpointMiddleware(req as any, res, (() => null) as any); - - expect(emulator.facilities.endpoints.get('http://localhost:5050/api/messages')).not.toBeNull(); - }); - - it('should push a new endpoint and set the proper ChannelService for Gov bots', () => { - const req = { - body: { - bot: { - id: '1234', - }, - }, - headers: { - 'x-emulator-botendpoint': 'http://localhost:5050/api/messages', - 'x-emulator-appid': '12e34', - 'x-emulator-apppassword': '54543', - 'x-emulator-channelservice': 'azureusgovernment', - }, - } as any; - getBotEndpointMiddleware(req as any, res, (() => null) as any); - - expect(emulator.facilities.endpoints.get('http://localhost:5050/api/messages')).not.toBeNull(); - const endpoint = emulator.facilities.endpoints.get('http://localhost:5050/api/messages'); - expect(endpoint.channelService).toEqual(usGovernmentAuthentication.channelService); - }); - - it('should retrieve the endpoint from the jwt when one exists', () => { - const req = { - jwt: { - appId: '1234', - }, - } as any; - - emulator.facilities.endpoints.push(null, { - botId: 'vfgdsfgds', - botUrl: 'http://localhost/api/messages', - msaAppId: '1234', - msaPassword: 'fdsa', - }); - - getBotEndpointMiddleware(req as any, res, (() => null) as any); - expect(req.botEndpoint).not.toBeNull(); - }); - - it('should update the msaAppId and msaAppPassword if the exist in the query', () => { - emulator.facilities.endpoints.push(null, { - botId: 'vfgdsfgds', - botUrl: 'http://localhost/api/messages', - msaAppId: 'oldAppId', - msaPassword: 'oldPassword', - }); - const bot = { role: 'bot', name: 'thebot', id: '456' }; - const req = { - headers: { - 'x-emulator-botendpoint': 'http://localhost:5050/api/messages', - 'x-emulator-appid': 'newAppId', - 'x-emulator-apppassword': 'newPassword', - }, - body: { - isGroup: false, - members: [{ id: '456', name: 'emulator', role: 'user' }], - bot, - conversationId: '007', - activity: null, - channelData: null, - } as ConversationParameters, - } as any; - getBotEndpointMiddleware(req as any, res, (() => null) as any); - expect(req.botEndpoint.msaAppId).toBe('newAppId'); - expect(req.botEndpoint.msaPassword).toBe('newPassword'); - }); - - it('should retrieve all conversations', () => { - const mockConversations = { - '1234abcd': { conversationId: '1234abcd', members: [] }, - '1234abcde': { conversationId: '1234abcde', members: [] }, - '1234abcdf': { conversationId: '1234abcdf', members: [] }, - }; - (emulator.facilities.conversations as any)['conversations'] = mockConversations; - const req = { params: { continuationToken: '1234abcde' } } as any; - const fetchConversationMiddleware = createFetchConversationMiddleware(emulator); - fetchConversationMiddleware(req as any, res, (() => null) as any); - expect(sentResponses[0][1]).toEqual({ - conversations: [ - { - id: '1234abcde', - members: [], - }, - { - id: '1234abcdf', - members: [], - }, - ], - }); - }); -}); - -function createConversationUtil(emulator: BotEmulator): Conversation { - // create the conversation with an activity - const bot = { role: 'bot', name: 'thebot', id: '456' }; - const req: any = { - botEndpoint: new BotEndpoint('12', '456', 'http://localhost:12345', '', '', false, '', {}), - body: { - isGroup: false, - members: [{ id: '456', name: 'emulator', role: 'user' }], - bot, - conversationId: '007', - activity: {} as Activity, - channelData: null, - } as ConversationParameters, - }; - const createConversationMiddleware = createConversation.bind({ - botId: bot.id, - })(emulator); - createConversationMiddleware(req as any, { send: () => null, end: () => null }, (() => null) as any); - - return emulator.facilities.conversations.conversationById('007|livechat'); -} - -function createEmulatorUtil(): BotEmulator { - const emulator = { - facilities: { logger: { logMessage: () => true } }, - } as any; - emulator.facilities.conversations = new ConversationSet(); - emulator.facilities.users = new Users(); - emulator.facilities.users.currentUserId = '456'; - emulator.facilities.endpoints = new Endpoints(emulator); - emulator.facilities.logger = { logActivity: () => null } as any; - emulator.facilities.attachments = new Attachments(); - emulator.options = {}; - - return emulator; -} diff --git a/packages/emulator/core/src/conversations/registerRoutes.spec.ts b/packages/emulator/core/src/conversations/registerRoutes.spec.ts deleted file mode 100644 index e7988be3e..000000000 --- a/packages/emulator/core/src/conversations/registerRoutes.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import createJsonBodyParser from '../utils/jsonBodyParser'; - -import registerRoutes from './registerRoutes'; -import createConversation from './middleware/createConversation'; -import deleteActivity from './middleware/deleteActivity'; -import createFetchConversationMiddleware from './middleware/fetchConversation'; -import getActivityMembers from './middleware/getActivityMembers'; -import getBotEndpoint from './middleware/getBotEndpoint'; -import getConversationMembers from './middleware/getConversationMembers'; -import replyToActivity from './middleware/replyToActivity'; -import sendActivityToConversation from './middleware/sendActivityToConversation'; -import sendHistoryToConversation from './middleware/sendHistoryToConversation'; -import updateActivity from './middleware/updateActivity'; -import uploadAttachment from './middleware/uploadAttachment'; - -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('../utils/botFrameworkAuthentication', () => jest.fn(() => null)); -jest.mock('../utils/jsonBodyParser', () => jest.fn(() => null)); -jest.mock('./middleware/createConversation', () => jest.fn(() => null)); -jest.mock('./middleware/deleteActivity', () => jest.fn(() => null)); -jest.mock('./middleware/fetchConversation', () => jest.fn(() => null)); -jest.mock('./middleware/getActivityMembers', () => jest.fn(() => null)); -jest.mock('./middleware/getBotEndpoint', () => jest.fn(() => null)); -jest.mock('./middleware/getConversationMembers', () => jest.fn(() => null)); -jest.mock('./middleware/replyToActivity', () => jest.fn(() => null)); -jest.mock('./middleware/sendActivityToConversation', () => jest.fn(() => null)); -jest.mock('./middleware/sendHistoryToConversation', () => jest.fn(() => null)); -jest.mock('./middleware/updateActivity', () => jest.fn(() => null)); -jest.mock('./middleware/uploadAttachment', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const post = jest.fn(() => null); - const del = jest.fn(() => null); - const put = jest.fn(() => null); - const server: any = { - get, - post, - del, - put, - }; - const uses = []; - const emulator: any = { - options: { fetch: () => null }, - }; - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulator.options.fetch); - const botEndpoint = getBotEndpoint(emulator); - const facility = getFacility('conversations'); - const jsonBodyParser = createJsonBodyParser(); - const fetchConversation = createFetchConversationMiddleware(emulator); - registerRoutes(emulator, server, uses); - - expect(post).toHaveBeenCalledWith( - '/v3/conversations', - ...uses, - verifyBotFramework, - jsonBodyParser, - botEndpoint, - facility, - getRouteName('createConversation'), - createConversation(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('sendToConversation'), - sendActivityToConversation(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities/history', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('sendToConversation'), - sendHistoryToConversation(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('replyToActivity'), - replyToActivity(emulator) - ); - - expect(put).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateActivity'), - updateActivity(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('deleteActivity'), - deleteActivity(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/members', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('getConversationMembers'), - getConversationMembers(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/activities/:activityId/members', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('getActivityMembers'), - getActivityMembers(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/conversations/:conversationId/attachments', - ...uses, - verifyBotFramework, - jsonBodyParser, - facility, - getRouteName('uploadAttachment'), - uploadAttachment(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/conversations/registerRoutes.ts b/packages/emulator/core/src/conversations/registerRoutes.ts deleted file mode 100644 index 38eaa8d24..000000000 --- a/packages/emulator/core/src/conversations/registerRoutes.ts +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import createJsonBodyParser from '../utils/jsonBodyParser'; - -import createConversation from './middleware/createConversation'; -import deleteActivity from './middleware/deleteActivity'; -import createFetchConversationMiddleware from './middleware/fetchConversation'; -import getActivityMembers from './middleware/getActivityMembers'; -import getBotEndpoint from './middleware/getBotEndpoint'; -import getConversationMembers from './middleware/getConversationMembers'; -import replyToActivity from './middleware/replyToActivity'; -import sendActivityToConversation from './middleware/sendActivityToConversation'; -import sendHistoryToConversation from './middleware/sendHistoryToConversation'; -import updateActivity from './middleware/updateActivity'; -import uploadAttachment from './middleware/uploadAttachment'; -import getConversations from './middleware/getConversations'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - // TODO: Check if it works without MSA App ID - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(botEmulator.options.fetch); - // const verifyBotFramework = botEmulator.msaAppId ? - // createBotFrameworkAuthenticationMiddleware(botEmulator.options.fetch) : []; - const botEndpoint = getBotEndpoint(botEmulator); - const facility = getFacility('conversations'); - const jsonBodyParser = createJsonBodyParser(); - const fetchConversation = createFetchConversationMiddleware(botEmulator); - - server.post( - '/v3/conversations', - ...uses, - verifyBotFramework, - jsonBodyParser, - botEndpoint, - facility, - getRouteName('createConversation'), - createConversation(botEmulator) - ); - - server.post( - '/v3/conversations/:conversationId/activities', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('sendToConversation'), - sendActivityToConversation(botEmulator) - ); - - server.post( - '/v3/conversations/:conversationId/activities/history', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('sendToConversation'), - sendHistoryToConversation(botEmulator) - ); - - server.post( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('replyToActivity'), - replyToActivity(botEmulator) - ); - - server.put( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateActivity'), - updateActivity(botEmulator) - ); - - server.del( - '/v3/conversations/:conversationId/activities/:activityId', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('deleteActivity'), - deleteActivity(botEmulator) - ); - - server.get( - '/v3/conversations', - ...uses, - verifyBotFramework, - facility, - getRouteName('getConversations'), - getConversations(botEmulator) - ); - - server.get( - '/v3/conversations/:conversationId/members', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('getConversationMembers'), - getConversationMembers(botEmulator) - ); - - server.get( - '/v3/conversations/:conversationId/activities/:activityId/members', - ...uses, - verifyBotFramework, - fetchConversation, - facility, - getRouteName('getActivityMembers'), - getActivityMembers(botEmulator) - ); - - server.post( - '/v3/conversations/:conversationId/attachments', - ...uses, - verifyBotFramework, - jsonBodyParser, - facility, - getRouteName('uploadAttachment'), - uploadAttachment(botEmulator) - ); -} diff --git a/packages/emulator/core/src/directLine/middleware/directLineMiddleware.spec.ts b/packages/emulator/core/src/directLine/middleware/directLineMiddleware.spec.ts deleted file mode 100644 index b78fe4532..000000000 --- a/packages/emulator/core/src/directLine/middleware/directLineMiddleware.spec.ts +++ /dev/null @@ -1,507 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -/* eslint-disable typescript/camelcase */ -import * as HttpStatus from 'http-status-codes'; -import { ConversationParameters } from '@bfemulator/sdk-shared'; - -import { BotEmulator } from '../../botEmulator'; -import Conversation from '../../facility/conversation'; -import BotEndpoint from '../../facility/botEndpoint'; -import createConversation from '../../conversations/middleware/createConversation'; -import ConversationSet from '../../facility/conversationSet'; -import Users from '../../facility/users'; -import Attachments from '../../facility/attachments'; - -import getActivities from './getActivities'; -import getConversation from './getConversation'; -import options from './options'; -import postActivity from './postActivity'; -import reconnectToConversation from './reconnectToConversation'; -import startConversation from './startConversation'; -import stream from './stream'; -import upload from './upload'; - -jest.mock('electron', () => ({ - ipcMain: new Proxy( - {}, - { - get(): any { - return () => ({}); - }, - has() { - return true; - }, - } - ), - ipcRenderer: new Proxy( - {}, - { - get(): any { - return () => ({}); - }, - has() { - return true; - }, - } - ), -})); - -jest.mock('formidable', () => ({ - IncomingForm: class { - // jest won't allow the use of args in this callback signature unless they are prefaced with 'mock' - parse(req: any, callback: (mockErr: any, mockFields: any, mockFiles: any) => any) { - return callback(null, null, { activity: req.activity, file: req.file }); - } - }, -})); - -jest.mock('fs', () => ({ - readFileSync: () => '{}', -})); - -describe('The directLine middleware', () => { - let emulator: BotEmulator; - let res; - beforeEach(() => { - res = { - send: () => null, - end: () => null, - json: () => null, - contentType: '', - }; - emulator = { - facilities: { - logger: { - logMessage: () => true, - logActivity: () => true, - logException: () => null, - }, - }, - } as any; - emulator.facilities.conversations = new ConversationSet(); - emulator.facilities.users = new Users(); - emulator.facilities.users.currentUserId = '456'; - emulator.facilities.users.users = { - '456': { id: '456', name: 'emulator' }, - }; - emulator.facilities.attachments = new Attachments(); - // @ts-ignore - emulator.getServiceUrl = () => 'https://localhost:8888/api/message'; - emulator.options = { - // @ts-ignore - tunnelingServiceUrl: 'https://localhost:3333', - }; - }); - - it('should getActivities', () => { - const mockActivities = [ - { - type: 'conversationUpdate', - membersAdded: [ - { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - name: 'User', - }, - { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - }, - ], - channelId: 'emulator', - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - id: '6e9e1e00-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:08-07:00', - recipient: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - timestamp: '2018-09-20T15:47:08.895Z', - from: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - name: 'User', - }, - serviceUrl: 'https://a457e760.ngrok.io', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - text: 'Hello, I am the Contoso Cafe Bot!', - inputHint: 'acceptingInput', - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6edf1ea0-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:09-07:00', - timestamp: '2018-09-20T15:47:09.322Z', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - text: 'I can help book a table, find cafe locations and more..', - inputHint: 'acceptingInput', - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6f141151-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:09-07:00', - timestamp: '2018-09-20T15:47:09.669Z', - }, - { - type: 'message', - serviceUrl: 'https://a457e760.ngrok.io', - channelId: 'emulator', - from: { - id: 'http://localhost:3978/api/messages', - name: 'Bot', - role: 'bot', - }, - conversation: { - id: '6e8b5950-bcec-11e8-97ca-bd586926880a|livechat', - }, - recipient: { - id: '0a441b55-d1d6-4015-bbb4-2e7f44fa9f42', - role: 'user', - }, - attachments: [ - { - contentType: 'application/vnd.microsoft.card.adaptive', - content: { - type: 'AdaptiveCard', - horizontalAlignment: 'Center', - separator: true, - height: 'stretch', - body: [ - { - type: 'ColumnSet', - horizontalAlignment: 'Center', - spacing: 'large', - height: 'stretch', - columns: [ - { - type: 'Column', - spacing: 'large', - items: [ - { - type: 'TextBlock', - size: 'extraLarge', - weight: 'bolder', - text: 'Contoso Cafe', - }, - { - type: 'TextBlock', - size: 'Medium', - text: "Hello, I'm the Cafe bot! How can I be of help today?", - wrap: true, - }, - ], - }, - { - type: 'Column', - spacing: 'small', - items: [ - { - type: 'Image', - horizontalAlignment: 'center', - url: 'http://contosocafeontheweb.azurewebsites.net/assets/contoso_logo_black.png', - size: 'medium', - }, - ], - width: 'auto', - }, - ], - }, - ], - actions: [ - { - type: 'Action.Submit', - title: 'Book table', - data: { - intent: 'Book_Table', - }, - }, - { - type: 'Action.Submit', - title: 'What can you do?', - data: { - intent: 'What_can_you_do', - }, - }, - ], - $schema: 'http://adaptivecards.io/schemas/adaptive-card.json', - version: '1.0', - }, - }, - ], - replyToId: '6e9fcbb0-bcec-11e8-a0e5-939fd8c687fd', - id: '6f47f290-bcec-11e8-a0e5-939fd8c687fd', - localTimestamp: '2018-09-20T08:47:10-07:00', - timestamp: '2018-09-20T15:47:10.009Z', - }, - ]; - - const conversation = createConversationUtil(emulator); - conversation.feedActivities(mockActivities); - - const getActivitiesMiddleware = getActivities(emulator); - const req = { - query: { watermark: 0 }, - conversation, - }; - - const jsonSpy = jest.spyOn(res, 'json'); - getActivitiesMiddleware(req as any, res, (() => null) as any); - // mockActivities.forEach(activity => activity.localTimestamp = jasmine.any(String) as any); - expect(jsonSpy).toHaveBeenCalledWith(HttpStatus.OK, { - activities: mockActivities, - watermark: mockActivities.length, - }); - }); - - it('should get a conversation', () => { - const conversation = createConversationUtil(emulator); - const getConversationMiddleware = getConversation(emulator); - const req = { - params: { conversationId: conversation.conversationId }, - conversation: null, - }; - - getConversationMiddleware(req as any, res, (() => null) as any); - - expect(req.conversation).toBe(conversation); - }); - - it('should send a 200 when the OPTIONS pre-flight is requested', () => { - const sendSpy = jest.spyOn(res, 'send'); - options(emulator)({} as any, res, (() => null) as any); - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK); - }); - - it('should post activity to the bot', async () => { - const mockActivity = { - conversation: { - id: 'vY4U6Daqs1rrWK5uIDlp8eFHHq0=', - }, - id: '5', - recipient: { - id: 'jopVZjYqyE3A5EnA8dYrlA+Mubw=', - name: 'cafebot', - role: 'bot', - }, - from: { - id: 'aqMkJoc/DqiL+cgiJhoUJCxSZ+U=', - name: 'vishwac', - role: 'user', - }, - text: 'How about seattle?', - timestamp: '2018-08-28T16:34:57.100Z', - type: 'message', - channelId: 'chatdown', - }; - - const conversation = createConversationUtil(emulator); - const postActivityMiddleware = postActivity(emulator); - const sendSpy = jest.spyOn(res, 'send'); - const req = { - conversation, - body: mockActivity, - params: { - conversationId: conversation.conversationId, - }, - }; - - await postActivityMiddleware(req as any, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.OK, { id: '5' }); - expect((conversation as any).activities[0]).toEqual({ - activity: { - ...mockActivity, - serviceUrl: 'https://localhost:8888/api/message', - channelId: 'emulator', - recipient: { - id: '456', - name: 'Bot', - role: 'bot', - }, - timestamp: jasmine.any(String), - localTimestamp: jasmine.any(String), - }, - watermark: 0, - }); - }); - - it('should reconnect to the conversation', () => { - const conversation = createConversationUtil(emulator); - const reconnectToConversationMiddleware = reconnectToConversation(emulator); - const req = { - conversation, - params: { conversationId: conversation.conversationId }, - }; - - const jsonSpy = jest.spyOn(res, 'json'); - reconnectToConversationMiddleware(req as any, res, (() => null) as any); - - expect(jsonSpy).toHaveBeenCalledWith(HttpStatus.OK, { - conversationId: 'transcript-007|livechat', - expires_in: 2147483647, - streamUrl: '', - token: 'transcript-007|livechat', - }); - }); - - describe('when starting a new conversation', () => { - it('should create a new conversation if one does not already exist', async () => { - const req = { - header: () => 'bm90aGluZw.eyJjb252ZXJzYXRpb25JZCI6InRyYW5zY3JpcHQtMDA3In0=.7gjdshgfdsk98458205jfds9843fjds', - botEndpoint: new BotEndpoint('12', '456', 'http://localhost:12345', '', '', false, '', { - fetch: async () => true, - }), - conversation: null, - }; - const jsonSpy = jest.spyOn(res, 'json'); - await startConversation(emulator)(req as any, res, (() => null) as any); - - expect(jsonSpy).toHaveBeenCalledWith(HttpStatus.CREATED, { - conversationId: jasmine.any(String), - expires_in: 2147483647, - streamUrl: '', - token: '12', - }); - expect(req.conversation).toBeTruthy(); - }); - - it('should add members when the conversation exists', async () => { - const conversation = createConversationUtil(emulator); - const req = { - header: () => 'Bearer eyJjb252ZXJzYXRpb25JZCI6InRyYW5zY3JpcHQtMDA3In0=', - botEndpoint: new BotEndpoint('456', '1234', 'http://localhost:12345', '', '', false, '', { - fetch: async () => true, - }), - conversation: null, - }; - const jsonSpy = jest.spyOn(res, 'json'); - await startConversation(emulator)(req as any, res, (() => null) as any); - - expect(jsonSpy).toHaveBeenCalledWith(HttpStatus.CREATED, { - conversationId: 'transcript-007|livechat', - expires_in: 2147483647, - streamUrl: '', - token: '456', - }); - expect(req.conversation).toBeTruthy(); - expect(conversation.members.length).toBe(2); - }); - }); - - it('should send a 501 when stream is requested', () => { - const streamMiddleware = stream(emulator); - const sendSpy = jest.spyOn(res, 'send'); - streamMiddleware({} as any, res, (() => null) as any); - - expect(sendSpy).toHaveBeenCalledWith(HttpStatus.NOT_IMPLEMENTED); - }); - - it('should upload attachments', async () => { - const conversation = createConversationUtil(emulator, '00000'); - const req = { - conversation, - params: { conversationId: '00000' }, - activity: { path: '' }, - file: { - name: 'attachment', - type: 'image', - path: '/user/data/attachment.png', - }, - getContentType: () => 'multipart/form-data', - isChunked: () => true, - getContentLength: () => 8, - botEndpoint: conversation.botEndpoint, - }; - res.send = () => void 0; - await upload(emulator)(req as any, res, (() => null) as any); - await Promise.resolve(true); - await Promise.resolve(true); - const { activities } = conversation as any; - expect(activities.length).toBe(1); - expect(activities[0].activity.attachments[0].name).toEqual('attachment'); - }); -}); - -function createConversationUtil(emulator: BotEmulator, conversationId: string = 'transcript-007'): Conversation { - // create the conversation with an activity - const bot = { role: 'bot', name: 'thebot', id: '456' }; - const req: any = { - botEndpoint: new BotEndpoint('12', '456', 'http://localhost:12345', '', '', false, '', { - fetch: async () => ({ - json: async () => ({}), - text: async () => 'hello', - status: 200, - }), - }), - body: { - members: [{ id: '456', name: 'emulator', role: 'user' }], - bot, - conversationId, - } as ConversationParameters, - }; - const createConversationMiddleware = createConversation.bind({ - botId: bot.id, - })(emulator); - createConversationMiddleware(req as any, { send: () => null, end: () => null }, (() => null) as any); - - return emulator.facilities.conversations.conversationById(conversationId + '|livechat'); -} diff --git a/packages/emulator/core/src/directLine/registerRoutes.spec.ts b/packages/emulator/core/src/directLine/registerRoutes.spec.ts deleted file mode 100644 index 6bf5bdaa7..000000000 --- a/packages/emulator/core/src/directLine/registerRoutes.spec.ts +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getBotEndpoint from '../middleware/getBotEndpoint'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import getActivities from './middleware/getActivities'; -import getConversation from './middleware/getConversation'; -import options from './middleware/options'; -import postActivity from './middleware/postActivity'; -import reconnectToConversation from './middleware/reconnectToConversation'; -import startConversation from './middleware/startConversation'; -import stream from './middleware/stream'; -import upload from './middleware/upload'; -import registerRoutes from './registerRoutes'; - -jest.mock('../middleware/getBotEndpoint', () => jest.fn(() => null)); -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('../utils/jsonBodyParser', () => jest.fn(() => null)); -jest.mock('./middleware/getActivities', () => jest.fn(() => null)); -jest.mock('./middleware/getConversation', () => jest.fn(() => null)); -jest.mock('./middleware/options', () => jest.fn(() => null)); -jest.mock('./middleware/postActivity', () => jest.fn(() => null)); -jest.mock('./middleware/reconnectToConversation', () => jest.fn(() => null)); -jest.mock('./middleware/startConversation', () => jest.fn(() => null)); -jest.mock('./middleware/stream', () => jest.fn(() => null)); -jest.mock('./middleware/upload', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const post = jest.fn(() => null); - const opts = jest.fn(() => null); - const server: any = { - get, - post, - opts, - }; - const uses = []; - const emulator: any = { - options: { fetch: () => null }, - }; - const jsonBodyParser = createJsonBodyParserMiddleware(); - const botEndpoint = getBotEndpoint(emulator); - const conversation = getConversation(emulator); - const facility = getFacility('directline'); - registerRoutes(emulator, server, uses); - - expect(opts).toHaveBeenCalledWith('/v3/directline', ...uses, facility, getRouteName('options'), options(emulator)); - - expect(post).toHaveBeenCalledWith( - '/v3/directline/conversations', - ...uses, - botEndpoint, - jsonBodyParser, - facility, - getRouteName('startConversation'), - startConversation(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/directline/conversations/:conversationId', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('reconnectToConversation'), - reconnectToConversation(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/directline/conversations/:conversationId/activities', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('getActivities'), - getActivities(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/directline/conversations/:conversationId/activities', - ...uses, - jsonBodyParser, - botEndpoint, - conversation, - facility, - getRouteName('postActivity'), - postActivity(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/v3/directline/conversations/:conversationId/upload', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('upload'), - upload(emulator) - ); - - expect(get).toHaveBeenCalledWith( - '/v3/directline/conversations/:conversationId/stream', - ...uses, - facility, - getRouteName('stream'), - stream(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/directLine/registerRoutes.ts b/packages/emulator/core/src/directLine/registerRoutes.ts deleted file mode 100644 index cdcbcd778..000000000 --- a/packages/emulator/core/src/directLine/registerRoutes.ts +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getBotEndpoint from '../middleware/getBotEndpoint'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import getActivities from './middleware/getActivities'; -import getConversation from './middleware/getConversation'; -import options from './middleware/options'; -import postActivity from './middleware/postActivity'; -import reconnectToConversation from './middleware/reconnectToConversation'; -import startConversation from './middleware/startConversation'; -import stream from './middleware/stream'; -import upload from './middleware/upload'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - const jsonBodyParser = createJsonBodyParserMiddleware(); - const botEndpoint = getBotEndpoint(botEmulator); - const conversation = getConversation(botEmulator); - const facility = getFacility('directline'); - - server.opts('/v3/directline', ...uses, facility, getRouteName('options'), options(botEmulator)); - - server.post( - '/v3/directline/conversations', - ...uses, - botEndpoint, - jsonBodyParser, - facility, - getRouteName('startConversation'), - startConversation(botEmulator) - ); - - server.get( - '/v3/directline/conversations/:conversationId', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('reconnectToConversation'), - reconnectToConversation(botEmulator) - ); - - server.get( - '/v3/directline/conversations/:conversationId/activities', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('getActivities'), - getActivities(botEmulator) - ); - - server.post( - '/v3/directline/conversations/:conversationId/activities', - ...uses, - jsonBodyParser, - botEndpoint, - conversation, - facility, - getRouteName('postActivity'), - postActivity(botEmulator) - ); - - server.post( - '/v3/directline/conversations/:conversationId/upload', - ...uses, - botEndpoint, - conversation, - facility, - getRouteName('upload'), - upload(botEmulator) - ); - - server.get( - '/v3/directline/conversations/:conversationId/stream', - ...uses, - facility, - getRouteName('stream'), - stream(botEmulator) - ); -} diff --git a/packages/emulator/core/src/emulator/middleware/contactRemoved.ts b/packages/emulator/core/src/emulator/middleware/contactRemoved.ts deleted file mode 100644 index ff0a76c4c..000000000 --- a/packages/emulator/core/src/emulator/middleware/contactRemoved.ts +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function contactRemoved(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - try { - await req.conversation.sendContactRemoved(); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/deleteUserData.ts b/packages/emulator/core/src/emulator/middleware/deleteUserData.ts deleted file mode 100644 index 15bc67efa..000000000 --- a/packages/emulator/core/src/emulator/middleware/deleteUserData.ts +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function deleteUserData(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - try { - await req.conversation.sendDeleteUserData(); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/getConversationEndpoint.spec.ts b/packages/emulator/core/src/emulator/middleware/getConversationEndpoint.spec.ts deleted file mode 100644 index 0f02386d6..000000000 --- a/packages/emulator/core/src/emulator/middleware/getConversationEndpoint.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -import { BotEmulator } from '../../botEmulator'; -import ConversationSet from '../../facility/conversationSet'; -import Users from '../../facility/users'; -import Endpoints from '../../facility/endpointSet'; -import Attachments from '../../facility/attachments'; -import BotEndpoint from '../../facility/botEndpoint'; - -import getConversationEndpoint from './getConversationEndpoint'; - -describe('The conversations middleware', () => { - let emulator: BotEmulator; - let res; - let sentResponses; - beforeEach(() => { - sentResponses = []; - res = { - json: (...args) => sentResponses.push(args), - end: () => null, - contentType: '', - }; - emulator = createEmulatorUtil(); - }); - - it('should get the endpoint from the specific conversation', () => { - const targetEndpoint = new BotEndpoint('1234'); - const targetConversation = emulator.facilities.conversations.newConversation(emulator, targetEndpoint, { - name: 'User', - id: '1234', - }); - const getConversationEndpointMiddleware = getConversationEndpoint(emulator); - const req = { params: { conversationId: targetConversation.conversationId } }; - getConversationEndpointMiddleware(req as any, res, (() => null) as any); - - expect(sentResponses[0][0]).toBe(200); - expect(sentResponses[0][1]).toBe(targetEndpoint); - }); -}); - -function createEmulatorUtil(): BotEmulator { - const emulator = { - facilities: { logger: { logMessage: () => true } }, - } as any; - emulator.facilities.conversations = new ConversationSet(); - emulator.facilities.users = new Users(); - emulator.facilities.users.currentUserId = '456'; - emulator.facilities.endpoints = new Endpoints(emulator); - emulator.facilities.logger = { logActivity: () => null } as any; - emulator.facilities.attachments = new Attachments(); - emulator.options = {}; - - return emulator; -} diff --git a/packages/emulator/core/src/emulator/middleware/paymentComplete.ts b/packages/emulator/core/src/emulator/middleware/paymentComplete.ts deleted file mode 100644 index 2e3249864..000000000 --- a/packages/emulator/core/src/emulator/middleware/paymentComplete.ts +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function paymentComplete(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - const { checkoutSession, request, shippingAddress, shippingOptionId, payerPhone, payerEmail } = req.body[0]; - const args = [checkoutSession, request, shippingAddress, shippingOptionId, payerEmail, payerPhone]; - - try { - const response = await req.conversation.sendPaymentCompleteOperation.apply(req.conversation, args); - res.send(HttpStatus.OK, response); - } catch (err) { - sendErrorResponse(req, res, next, err); - res.send(HttpStatus.INTERNAL_SERVER_ERROR); - } - res.end(); - - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/ping.ts b/packages/emulator/core/src/emulator/middleware/ping.ts deleted file mode 100644 index ee8f0fe89..000000000 --- a/packages/emulator/core/src/emulator/middleware/ping.ts +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function ping(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - try { - await req.conversation.sendPing(); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/typing.ts b/packages/emulator/core/src/emulator/middleware/typing.ts deleted file mode 100644 index ae88dc083..000000000 --- a/packages/emulator/core/src/emulator/middleware/typing.ts +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function typing(botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - try { - await req.conversation.sendTyping(); - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/updateShippingAddress.ts b/packages/emulator/core/src/emulator/middleware/updateShippingAddress.ts deleted file mode 100644 index 867e78d78..000000000 --- a/packages/emulator/core/src/emulator/middleware/updateShippingAddress.ts +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function updateShippingAddress(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - const { checkoutSession, request, shippingAddress, shippingOptionId } = req.body[0]; - const args = [checkoutSession, request, shippingAddress, shippingOptionId]; - try { - const response = await req.conversation.sendUpdateShippingAddressOperation.apply(req.conversation, args); - const json = await response.json(); - res.send(HttpStatus.OK, json); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/middleware/updateShippingOption.ts b/packages/emulator/core/src/emulator/middleware/updateShippingOption.ts deleted file mode 100644 index a27f09b13..000000000 --- a/packages/emulator/core/src/emulator/middleware/updateShippingOption.ts +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -import { ConversationAware } from './fetchConversation'; - -export default function updateShippingOption(_botEmulator: BotEmulator) { - return async (req: ConversationAware, res: Restify.Response, next: Restify.Next): Promise => { - const { checkoutSession, request, shippingAddress, shippingOptionId } = req.body[0]; - const args = [checkoutSession, request, shippingAddress, shippingOptionId]; - try { - const response = await req.conversation.sendUpdateShippingOptionOperation.apply(req.conversation, args); - const json = await response.json(); - res.send(HttpStatus.OK, json); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - next(); - }; -} diff --git a/packages/emulator/core/src/emulator/registerRoutes.spec.ts b/packages/emulator/core/src/emulator/registerRoutes.spec.ts deleted file mode 100644 index 955e3e9a3..000000000 --- a/packages/emulator/core/src/emulator/registerRoutes.spec.ts +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import addUsers from './middleware/addUsers'; -import contactAdded from './middleware/contactAdded'; -import contactRemoved from './middleware/contactRemoved'; -import deleteUserData from './middleware/deleteUserData'; -import createFetchConversationMiddleware from './middleware/fetchConversation'; -import getUsers from './middleware/getUsers'; -import paymentComplete from './middleware/paymentComplete'; -import ping from './middleware/ping'; -import removeUsers from './middleware/removeUsers'; -import sendTokenResponse from './middleware/sendTokenResponse'; -import typing from './middleware/typing'; -import updateShippingAddress from './middleware/updateShippingAddress'; -import updateShippingOption from './middleware/updateShippingOption'; -import registerRoutes from './registerRoutes'; - -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('../utils/jsonBodyParser', () => jest.fn(() => null)); -jest.mock('./middleware/addUsers', () => jest.fn(() => null)); -jest.mock('./middleware/contactAdded', () => jest.fn(() => null)); -jest.mock('./middleware/contactRemoved', () => jest.fn(() => null)); -jest.mock('./middleware/deleteUserData', () => jest.fn(() => null)); -jest.mock('./middleware/fetchConversation', () => jest.fn(() => null)); -jest.mock('./middleware/getUsers', () => jest.fn(() => null)); -jest.mock('./middleware/paymentComplete', () => jest.fn(() => null)); -jest.mock('./middleware/ping', () => jest.fn(() => null)); -jest.mock('./middleware/removeUsers', () => jest.fn(() => null)); -jest.mock('./middleware/sendTokenResponse', () => jest.fn(() => null)); -jest.mock('./middleware/typing', () => jest.fn(() => null)); -jest.mock('./middleware/updateShippingAddress', () => jest.fn(() => null)); -jest.mock('./middleware/updateShippingOption', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const post = jest.fn(() => null); - const del = jest.fn(() => null); - const server: any = { - get, - post, - del, - }; - const uses = []; - const emulator: any = { - options: { fetch: () => null }, - }; - const fetchConversation = createFetchConversationMiddleware(emulator); - const jsonBodyParser = createJsonBodyParserMiddleware(); - const facility = getFacility('emulator'); - registerRoutes(emulator, server, uses); - - expect(get).toHaveBeenCalledWith( - '/emulator/:conversationId/users', - fetchConversation, - facility, - getRouteName('getUsers'), - getUsers(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/users', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('addUsers'), - addUsers(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/emulator/:conversationId/users', - fetchConversation, - facility, - getRouteName('removeUsers'), - removeUsers(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/contacts', - fetchConversation, - facility, - getRouteName('contactAdded'), - contactAdded(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/emulator/:conversationId/contacts', - fetchConversation, - facility, - getRouteName('contactRemoved'), - contactRemoved(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/typing', - fetchConversation, - facility, - getRouteName('typing'), - typing(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/ping', - fetchConversation, - facility, - getRouteName('ping'), - ping(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/emulator/:conversationId/userdata', - fetchConversation, - facility, - getRouteName('deleteUserData'), - deleteUserData(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/invoke/updateShippingAddress', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateShippingAddress'), - updateShippingAddress(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/invoke/updateShippingOption', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateShippingOption'), - updateShippingOption(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/invoke/paymentComplete', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('paymentComplete'), - paymentComplete(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/emulator/:conversationId/invoke/sendTokenResponse', - jsonBodyParser, - facility, - getRouteName('sendTokenResponse'), - sendTokenResponse(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/emulator/registerRoutes.ts b/packages/emulator/core/src/emulator/registerRoutes.ts deleted file mode 100644 index 2bf74f85d..000000000 --- a/packages/emulator/core/src/emulator/registerRoutes.ts +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import addUsers from './middleware/addUsers'; -import contactAdded from './middleware/contactAdded'; -import contactRemoved from './middleware/contactRemoved'; -import deleteUserData from './middleware/deleteUserData'; -import createFetchConversationMiddleware from './middleware/fetchConversation'; -import getUsers from './middleware/getUsers'; -import paymentComplete from './middleware/paymentComplete'; -import ping from './middleware/ping'; -import removeUsers from './middleware/removeUsers'; -import sendTokenResponse from './middleware/sendTokenResponse'; -import typing from './middleware/typing'; -import updateShippingAddress from './middleware/updateShippingAddress'; -import updateShippingOption from './middleware/updateShippingOption'; -import getConversationEndpoint from './middleware/getConversationEndpoint'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - const fetchConversation = createFetchConversationMiddleware(botEmulator); - const jsonBodyParser = createJsonBodyParserMiddleware(); - const facility = getFacility('emulator'); - - server.get('/emulator/:conversationId/endpoint', getConversationEndpoint(botEmulator)); - - server.get( - '/emulator/:conversationId/users', - fetchConversation, - facility, - getRouteName('getUsers'), - getUsers(botEmulator) - ); - - server.post( - '/emulator/:conversationId/users', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('addUsers'), - addUsers(botEmulator) - ); - - server.del( - '/emulator/:conversationId/users', - fetchConversation, - facility, - getRouteName('removeUsers'), - removeUsers(botEmulator) - ); - - server.post( - '/emulator/:conversationId/contacts', - fetchConversation, - facility, - getRouteName('contactAdded'), - contactAdded(botEmulator) - ); - - server.del( - '/emulator/:conversationId/contacts', - fetchConversation, - facility, - getRouteName('contactRemoved'), - contactRemoved(botEmulator) - ); - - server.post( - '/emulator/:conversationId/typing', - fetchConversation, - facility, - getRouteName('typing'), - typing(botEmulator) - ); - - server.post('/emulator/:conversationId/ping', fetchConversation, facility, getRouteName('ping'), ping(botEmulator)); - - server.del( - '/emulator/:conversationId/userdata', - fetchConversation, - facility, - getRouteName('deleteUserData'), - deleteUserData(botEmulator) - ); - - server.post( - '/emulator/:conversationId/invoke/updateShippingAddress', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateShippingAddress'), - updateShippingAddress(botEmulator) - ); - - server.post( - '/emulator/:conversationId/invoke/updateShippingOption', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('updateShippingOption'), - updateShippingOption(botEmulator) - ); - - server.post( - '/emulator/:conversationId/invoke/paymentComplete', - jsonBodyParser, - fetchConversation, - facility, - getRouteName('paymentComplete'), - paymentComplete(botEmulator) - ); - - server.post( - '/emulator/:conversationId/invoke/sendTokenResponse', - jsonBodyParser, - facility, - getRouteName('sendTokenResponse'), - sendTokenResponse(botEmulator) - ); -} diff --git a/packages/emulator/core/src/facility/botState.spec.ts b/packages/emulator/core/src/facility/botState.spec.ts deleted file mode 100644 index 13a3d5702..000000000 --- a/packages/emulator/core/src/facility/botState.spec.ts +++ /dev/null @@ -1,176 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { ErrorCodes } from '@bfemulator/sdk-shared'; -import * as HttpStatus from 'http-status-codes'; - -import createAPIException from '../utils/createResponse/apiException'; - -import BotState from './botState'; -import botDataKey from './botDataKey'; - -let mockApproximatedObjectSize; -jest.mock('../utils/approximateObjectSize', () => jest.fn(() => mockApproximatedObjectSize)); - -describe('botState', () => { - beforeEach(() => { - mockApproximatedObjectSize = 64; - }); - - it('should get bot data when the record exists', () => { - const channelId = 'channel1'; - const convoId = 'convo1'; - const userId = 'user1'; - const dataKey = botDataKey(channelId, convoId, userId); - const botData = { data: 'I am bot data!' }; - const mockLogDeprecationWarning = jest.fn(() => null); - const botState = new BotState(null, null); - (botState as any).botDataStore = { [dataKey]: botData }; - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - - const data = botState.getBotData(channelId, convoId, userId); - - expect(data).toBe(botData); - expect(mockLogDeprecationWarning).toHaveBeenCalledWith(convoId); - }); - - it('should get null bot data when the record does not exist', () => { - const mockLogDeprecationWarning = jest.fn(() => null); - const botState = new BotState(null, null); - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - - const data = botState.getBotData('channel1', 'convo1', 'user1'); - - expect(data).toEqual({ data: null, eTag: '*' }); - }); - - it('should set bot data', () => { - const channelId = 'channel1'; - const convoId = 'convo1'; - const userId = 'user1'; - const dataKey = botDataKey(channelId, convoId, userId); - const mockLogDeprecationWarning = jest.fn(() => null); - const botState = new BotState(null, null); - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - const botData: any = { data: 'I am bot data!' }; - - const data = botState.setBotData(channelId, convoId, userId, botData); - - expect(mockLogDeprecationWarning).toHaveBeenCalledWith(convoId); - expect(data.eTag).toEqual(jasmine.any(String)); - expect(data.data).toBe(botData.data); - expect((botState as any).botDataStore[dataKey]).toBe(data); - }); - - it('should delete the record when trying to set bot data with invalid data', () => { - const channelId = 'channel1'; - const convoId = 'convo1'; - const userId = 'user1'; - const dataKey = botDataKey(channelId, convoId, userId); - const mockLogDeprecationWarning = jest.fn(() => null); - const botData: any = { data: null }; - const botState = new BotState(null, null); - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - (botState as any).botDataStore[dataKey] = botData; - - expect((botState as any).botDataStore[dataKey]).toBe(botData); - - const data = botState.setBotData(channelId, convoId, userId, botData); - - expect(mockLogDeprecationWarning).toHaveBeenCalledWith(convoId); - expect(data.eTag).toBe('*'); - expect(data.data).toBe(null); - expect((botState as any).botDataStore[dataKey]).toBe(undefined); - }); - - it('should throw when the bot data etags are mismatched', () => { - const channelId = 'channel1'; - const convoId = 'convo1'; - const userId = 'user1'; - const dataKey = botDataKey(channelId, convoId, userId); - const mockLogDeprecationWarning = jest.fn(() => null); - const oldBotData: any = { data: 'I am bot data!', eTag: 'Modified on Thursday' }; - const newBotData: any = { data: 'I am bot data!', eTag: 'Modified on Friday' }; - const botState = new BotState(null, null); - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - (botState as any).botDataStore[dataKey] = oldBotData; - - try { - botState.setBotData(channelId, convoId, userId, newBotData); - } catch (e) { - expect(e).toEqual( - createAPIException(HttpStatus.PRECONDITION_FAILED, ErrorCodes.BadArgument, 'The data is changed') - ); - } - }); - - it('should throw when the bot data is larger than the size limit', () => { - const mockLogDeprecationWarning = jest.fn(() => null); - const botState = new BotState(null, null); - mockApproximatedObjectSize = 9999; // ensure that the size exceeds the limit - botState.stateSizeLimitKB = 1; - (botState as any).logBotStateApiDeprecationWarning = mockLogDeprecationWarning; - const botData: any = { data: 'I am bot data!' }; - - try { - botState.setBotData('', '', '', botData); - } catch (e) { - expect(e).toEqual( - createAPIException( - HttpStatus.BAD_REQUEST, - ErrorCodes.MessageSizeTooBig, - 'State size exceeded configured limit.' - ) - ); - } - }); - - it('should delete bot data', () => { - const userId = '1234'; - const dataKey1 = botDataKey('channel1', 'convo1', userId); - const dataKey2 = botDataKey('channel1', 'convo2', userId); - const botData1 = { data: 'I am some bot data!' }; - const botData2 = { data: 'I am some other bot data!' }; - const botState = new BotState(null, null); - (botState as any).botDataStore = { - [dataKey1]: botData1, - [dataKey2]: botData2, - }; - - expect(Object.keys((botState as any).botDataStore)).toHaveLength(2); - - botState.deleteBotData(userId); - - expect(Object.keys((botState as any).botDataStore)).toHaveLength(0); - }); -}); diff --git a/packages/emulator/core/src/facility/botState.ts b/packages/emulator/core/src/facility/botState.ts deleted file mode 100644 index cb15beb80..000000000 --- a/packages/emulator/core/src/facility/botState.ts +++ /dev/null @@ -1,133 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { BotData, ErrorCodes, externalLinkItem, LogLevel, textItem } from '@bfemulator/sdk-shared'; -import * as HttpStatus from 'http-status-codes'; - -import approximateObjectSize from '../utils/approximateObjectSize'; -import { BotEmulator } from '../botEmulator'; -import createAPIException from '../utils/createResponse/apiException'; - -import Conversation from './conversation'; -import botDataKey from './botDataKey'; - -export default class BotState { - private botDataStore: { [key: string]: BotData } = {}; - - constructor(public botEmulator: BotEmulator, public stateSizeLimitKB: number) {} - - public getBotData(channelId: string, conversationId: string, userId: string): BotData { - this.logBotStateApiDeprecationWarning(conversationId); - - const key = botDataKey(channelId, conversationId, userId); - - return ( - this.botDataStore[key] || { - data: null, - eTag: '*', - } - ); - } - - public setBotData(channelId: string, conversationId: string, userId: string, incomingData: BotData): BotData { - this.logBotStateApiDeprecationWarning(conversationId); - - const key = botDataKey(channelId, conversationId, userId); - const oldData = this.botDataStore[key]; - - if ( - oldData && - oldData.eTag && - oldData.eTag.length > 0 && - incomingData.eTag !== '*' && - oldData.eTag !== incomingData.eTag - ) { - throw createAPIException(HttpStatus.PRECONDITION_FAILED, ErrorCodes.BadArgument, 'The data is changed'); - } - - if (this.stateSizeLimitKB > 0 && approximateObjectSize(incomingData) > this.stateSizeLimitKB * 1024) { - throw createAPIException( - HttpStatus.BAD_REQUEST, - ErrorCodes.MessageSizeTooBig, - 'State size exceeded configured limit.' - ); - } - - const newData: BotData = { - eTag: Date.now().toString(), - data: incomingData.data, - }; - - if (!incomingData.data) { - delete this.botDataStore[key]; - newData.eTag = '*'; - } else { - this.botDataStore[key] = newData; - } - - return newData; - } - - public deleteBotData(userId: string) { - const keys = Object.keys(this.botDataStore); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - - if (key.endsWith(`!${userId}`)) { - delete this.botDataStore[key]; - } - } - } - - private logBotStateApiDeprecationWarning(conversationId: string) { - const conversation: Conversation = this.botEmulator.facilities.conversations.conversationById(conversationId); - - if (conversation && !conversation.stateApiDeprecationWarningShown) { - conversation.stateApiDeprecationWarningShown = true; - - this.botEmulator.facilities.logger.logMessage( - conversationId, - textItem( - LogLevel.Warn, - 'Warning: The Bot Framework State API is not recommended for production ' + - 'environments, and may be deprecated in a future release.' - ), - externalLinkItem( - 'Learn how to implement your own storage adapter.', - 'https://aka.ms/botframework-state-service' - ) - ); - } - } -} diff --git a/packages/emulator/core/src/index.ts b/packages/emulator/core/src/index.ts deleted file mode 100644 index e6562779a..000000000 --- a/packages/emulator/core/src/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import Conversation from './facility/conversation'; -import ConversationSet from './facility/conversationSet'; -import Users from './facility/users'; -export * from './botEmulator'; - -export { Conversation, ConversationSet, Users }; diff --git a/packages/emulator/core/src/session/registerRoutes.ts b/packages/emulator/core/src/session/registerRoutes.ts deleted file mode 100644 index 4dc148b4b..000000000 --- a/packages/emulator/core/src/session/registerRoutes.ts +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as Restify from 'restify'; -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; - -import getSessionId from './middleware/getSessionId'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - const facility = getFacility('directline'); - - server.get('/v3/directline/session/getsessionid', facility, getRouteName('getSessionId'), getSessionId(botEmulator)); - - server.get('v4/token', (req: Restify.Request, res: Restify.Response) => { - const body = - '' + - 'Botframework Emulator' + - '' + - ''; - res.writeHead(200, { - 'Content-Length': Buffer.byteLength(body), - 'Content-Type': 'text/html', - }); - res.write(body); - res.end(); - }); -} diff --git a/packages/emulator/core/src/userToken/middleware/emulateOAuthCards.ts b/packages/emulator/core/src/userToken/middleware/emulateOAuthCards.ts deleted file mode 100644 index cdaf6df6a..000000000 --- a/packages/emulator/core/src/userToken/middleware/emulateOAuthCards.ts +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import OAuthLinkEncoder from '../../utils/oauthLinkEncoder'; -import sendErrorResponse from '../../utils/sendErrorResponse'; - -export default function emulateOAuthCards(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const emulate: string = req.params.emulate; - if (emulate) { - OAuthLinkEncoder.EmulateOAuthCards = emulate.toLowerCase() === 'true'; - } else { - OAuthLinkEncoder.EmulateOAuthCards = false; - } - res.send(HttpStatus.OK); - - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - }; -} diff --git a/packages/emulator/core/src/userToken/middleware/signOut.ts b/packages/emulator/core/src/userToken/middleware/signOut.ts deleted file mode 100644 index 420326b50..000000000 --- a/packages/emulator/core/src/userToken/middleware/signOut.ts +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import * as HttpStatus from 'http-status-codes'; -import * as Restify from 'restify'; - -import { BotEmulator } from '../../botEmulator'; -import BotEndpoint from '../../facility/botEndpoint'; -import sendErrorResponse from '../../utils/sendErrorResponse'; -import { TokenCache } from '../tokenCache'; -import { TokenParams } from '../TokenParams'; - -export default function signOut(botEmulator: BotEmulator) { - return (req: Restify.Request, res: Restify.Response, next: Restify.Next): any => { - try { - const params: TokenParams = req.params; - const botEndpoint: BotEndpoint = (req as any).botEndpoint; - TokenCache.deleteTokenFromCache(botEndpoint.botId, params.userId, params.connectionName); - - res.send(HttpStatus.OK); - res.end(); - } catch (err) { - sendErrorResponse(req, res, next, err); - } - }; -} diff --git a/packages/emulator/core/src/userToken/registerRoutes.spec.ts b/packages/emulator/core/src/userToken/registerRoutes.spec.ts deleted file mode 100644 index 3bfed9d2b..000000000 --- a/packages/emulator/core/src/userToken/registerRoutes.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import getBotEndpoint from '../middleware/getBotEndpoint'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import emulateOAuthCards from './middleware/emulateOAuthCards'; -import getToken from './middleware/getToken'; -import signOut from './middleware/signOut'; -import tokenResponse from './middleware/tokenResponse'; -import registerRoutes from './registerRoutes'; - -jest.mock('../middleware/getBotEndpoint', () => jest.fn(() => null)); -jest.mock('../middleware/getFacility', () => jest.fn(() => null)); -jest.mock('../middleware/getRouteName', () => jest.fn(() => null)); -jest.mock('../utils/botFrameworkAuthentication', () => jest.fn(() => null)); -jest.mock('../utils/jsonBodyParser', () => jest.fn(() => null)); -jest.mock('./middleware/emulateOAuthCards', () => jest.fn(() => null)); -jest.mock('./middleware/getToken', () => jest.fn(() => null)); -jest.mock('./middleware/signOut', () => jest.fn(() => null)); -jest.mock('./middleware/tokenResponse', () => jest.fn(() => null)); - -describe('registerRoutes', () => { - it('should register routes', () => { - const get = jest.fn(() => null); - const post = jest.fn(() => null); - const del = jest.fn(() => null); - const server: any = { - get, - post, - del, - }; - const uses = []; - const emulator: any = { - options: { fetch: () => null }, - }; - const jsonBodyParser = createJsonBodyParserMiddleware(); - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(emulator.options.fetch); - const botEndpoint = getBotEndpoint(emulator); - const facility = getFacility('api'); - registerRoutes(emulator, server, uses); - - expect(get).toHaveBeenCalledWith( - '/api/usertoken/GetToken', - verifyBotFramework, - botEndpoint, - facility, - getRouteName('getToken'), - getToken(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/api/usertoken/emulateOAuthCards', - verifyBotFramework, - facility, - getRouteName('emulateOAuthCards'), - emulateOAuthCards(emulator) - ); - - expect(del).toHaveBeenCalledWith( - '/api/usertoken/SignOut', - verifyBotFramework, - botEndpoint, - facility, - getRouteName('signOut'), - signOut(emulator) - ); - - expect(post).toHaveBeenCalledWith( - '/api/usertoken/tokenResponse', - ...uses, - jsonBodyParser, - facility, - getRouteName('tokenResponse'), - tokenResponse(emulator) - ); - }); -}); diff --git a/packages/emulator/core/src/userToken/registerRoutes.ts b/packages/emulator/core/src/userToken/registerRoutes.ts deleted file mode 100644 index cb509e661..000000000 --- a/packages/emulator/core/src/userToken/registerRoutes.ts +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { RequestHandler, Server } from 'restify'; - -import { BotEmulator } from '../botEmulator'; -import getBotEndpoint from '../middleware/getBotEndpoint'; -import getFacility from '../middleware/getFacility'; -import getRouteName from '../middleware/getRouteName'; -import createBotFrameworkAuthenticationMiddleware from '../utils/botFrameworkAuthentication'; -import createJsonBodyParserMiddleware from '../utils/jsonBodyParser'; - -import emulateOAuthCards from './middleware/emulateOAuthCards'; -import getToken from './middleware/getToken'; -import signOut from './middleware/signOut'; -import tokenResponse from './middleware/tokenResponse'; - -export default function registerRoutes(botEmulator: BotEmulator, server: Server, uses: RequestHandler[]) { - const jsonBodyParser = createJsonBodyParserMiddleware(); - const verifyBotFramework = createBotFrameworkAuthenticationMiddleware(botEmulator.options.fetch); - const botEndpoint = getBotEndpoint(botEmulator); - const facility = getFacility('api'); - - server.get( - '/api/usertoken/GetToken', - verifyBotFramework, - botEndpoint, - facility, - getRouteName('getToken'), - getToken(botEmulator) - ); - - server.post( - '/api/usertoken/emulateOAuthCards', - verifyBotFramework, - facility, - getRouteName('emulateOAuthCards'), - emulateOAuthCards(botEmulator) - ); - - server.del( - '/api/usertoken/SignOut', - verifyBotFramework, - botEndpoint, - facility, - getRouteName('signOut'), - signOut(botEmulator) - ); - - server.post( - '/api/usertoken/tokenResponse', - ...uses, - jsonBodyParser, - facility, - getRouteName('tokenResponse'), - tokenResponse(botEmulator) - ); -} diff --git a/packages/emulator/core/tsconfig.json b/packages/emulator/core/tsconfig.json deleted file mode 100644 index 7e0689c1c..000000000 --- a/packages/emulator/core/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "include": ["./src"], - "compilerOptions": { - "declarationDir": "lib" - } -} diff --git a/packages/sdk/shared/src/types/botEmulatorOptions.ts b/packages/sdk/shared/src/types/botEmulatorOptions.ts deleted file mode 100644 index cd4145347..000000000 --- a/packages/sdk/shared/src/types/botEmulatorOptions.ts +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// -// Microsoft Bot Framework: http://botframework.com -// -// Bot Framework Emulator Github: -// https://github.com/Microsoft/BotFramwork-Emulator -// -// Copyright (c) Microsoft Corporation -// All rights reserved. -// -// MIT License: -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -import { LogService } from './log/service'; -import { Logger } from './logger'; - -export interface BotEmulatorOptions { - fetch?: (url: string, options: any) => Promise; - loggerOrLogService?: Logger | LogService; - stateSizeLimitKB?: number; -} diff --git a/packages/sdk/shared/src/types/index.ts b/packages/sdk/shared/src/types/index.ts index 58285b1d7..8ce2d80e5 100644 --- a/packages/sdk/shared/src/types/index.ts +++ b/packages/sdk/shared/src/types/index.ts @@ -43,7 +43,6 @@ export * from './response'; export * from './apiException'; export * from './botConfigWithPath'; export * from './botData'; -export * from './botEmulatorOptions'; export * from './botEndpointOptions'; export * from './entity'; export * from './error'; diff --git a/packages/tools/package-lock.json b/packages/tools/package-lock.json index 11385ca14..05c4d37ab 100644 --- a/packages/tools/package-lock.json +++ b/packages/tools/package-lock.json @@ -1446,780 +1446,6 @@ } } } - }, - "restify": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/restify/-/restify-8.3.3.tgz", - "integrity": "sha512-E1xYBmC1gD3IUAeDhZx7VdmD69SSz8Ti5b69nwBgWCpTPIi3XImucPNnAtSEz5fHUW2F/arwSDUe1TPqt+5/zQ==", - "requires": { - "assert-plus": "^1.0.0", - "bunyan": "^1.8.12", - "csv": "^5.1.1", - "dtrace-provider": "^0.8.1", - "escape-regexp-component": "^1.0.2", - "ewma": "^2.0.1", - "find-my-way": "^2.0.1", - "formidable": "^1.2.1", - "http-signature": "^1.2.0", - "lodash": "^4.17.11", - "lru-cache": "^5.1.1", - "mime": "^2.4.3", - "negotiator": "^0.6.2", - "once": "^1.4.0", - "pidusage": "^2.0.17", - "qs": "^6.7.0", - "restify-errors": "^8.0.0", - "semver": "^6.1.1", - "send": "^0.16.2", - "spdy": "^4.0.0", - "uuid": "^3.3.2", - "vasync": "^2.2.0" - }, - "dependencies": { - "@netflix/nerror": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.2.tgz", - "integrity": "sha512-c01MmkM3Oi0BkTV4odMpr+58uXlxRKUPcu1ONR+sU3YAFAW4pP1j2b0opS9jX+an3ldpBJtiompzAEFZdlc8YQ==", - "requires": { - "assert-plus": "^1.0.0", - "extsprintf": "^1.4.0", - "lodash": "^4.17.15" - }, - "dependencies": { - "extsprintf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz", - "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=" - } - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "bunyan": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", - "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", - "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.10.6", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "csv": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/csv/-/csv-5.1.2.tgz", - "integrity": "sha512-2NA/Fp9FuRAJY6bu5mZsSyBFeqbDZjGg8z1WYETpBpuO30gyWOkxf9KjzBNEZiCsXuNxdQrU3rKrpejyucznMg==", - "requires": { - "csv-generate": "^3.2.3", - "csv-parse": "^4.4.5", - "csv-stringify": "^5.3.3", - "stream-transform": "^2.0.1" - } - }, - "csv-generate": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.2.3.tgz", - "integrity": "sha512-IcR3K0Nx+nJAkcU2eAglVR7DuHnxcuhUM2w2cR+aHOW7bZp2S5LyN2HF3zTkp6BV/DjR6ykoKznUm+AjnWcOKg==" - }, - "csv-parse": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.4.5.tgz", - "integrity": "sha512-koPV9m9AjNJCK3ig4ErgRJalZsLxWI7NP0Fd3+CO9hgDZt3FSljTeESnfWTbyRc8qk/3/LgX1s5naDqLxiuK9w==" - }, - "csv-stringify": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.3.3.tgz", - "integrity": "sha512-q8Qj+/lN74LRmG7Mg0LauE5WcnJOD5MEGe1gI57IYJCB61KWuEbAFHm1uIPDkI26aqElyBB57SlE2GGwq2EY5A==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" - }, - "dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "optional": true, - "requires": { - "nan": "^2.14.0" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-regexp-component": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", - "integrity": "sha1-nGO20LJf8qiMOtvRjFthrMO5+qI=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "ewma": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", - "integrity": "sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-decode-uri-component": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" - }, - "find-my-way": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.1.0.tgz", - "integrity": "sha512-Hdx6ctcrzkZH5y9EREHtXryXAgc5Bc8z5Cvoa61y9kaoYj2KU4yXD6h8b6u0NUkYPVmQQeRdf0AtG1kQxQ+ukQ==", - "requires": { - "fast-decode-uri-component": "^1.0.0", - "safe-regex2": "^2.0.0", - "semver-store": "^0.3.0" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "handle-thing": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", - "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true - }, - "mixme": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.3.2.tgz", - "integrity": "sha512-tilCZOvIhRETXJuTmxxpz8mgplF7gmFhcH05JuR/YL+JLO98gLRQ1Mk4XpYQxxbPMKupSOv+Bidw7EKv8wds1w==" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", - "optional": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "optional": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "optional": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "optional": true - }, - "pidusage": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.17.tgz", - "integrity": "sha512-N8X5v18rBmlBoArfS83vrnD0gIFyZkXEo7a5pAS2aT0i2OLVymFb2AzVg+v8l/QcXnE1JwZcaXR8daJcoJqtjw==", - "requires": { - "safe-buffer": "^5.1.2" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "qs": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.8.0.tgz", - "integrity": "sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "restify-errors": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-8.0.1.tgz", - "integrity": "sha512-EFQpxS828J0SBTNuJjh+rHD0OE8BoqnaxMAzuKHRNnGt5BV/212HHQIelZG4zjZYpTDEiuVAhQYHwSGSzAz0Ag==", - "requires": { - "@netflix/nerror": "^1.0.0", - "assert-plus": "^1.0.0", - "lodash": "^4.17.15", - "safe-json-stringify": "^1.0.4" - } - }, - "ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "optional": true, - "requires": { - "glob": "^6.0.1" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "optional": true - }, - "safe-regex2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", - "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", - "requires": { - "ret": "~0.2.0" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - }, - "dependencies": { - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - } - } - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "spdy": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", - "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - }, - "stream-transform": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.1.tgz", - "integrity": "sha512-GiTcO/rRvZP2R8WPwxmxCFP+Of1yIATuFAmYkvSLDfcD93X2WHiPwdgIqeFT2CvL1gyAsjQvu1nB6RDNQ5b2jw==", - "requires": { - "mixme": "^0.3.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "vasync": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.0.tgz", - "integrity": "sha1-z951GGChWCLbOxMrxZsRakra8Bs=", - "requires": { - "verror": "1.10.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - } - } } } }