diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +node_modules diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..62d6d0d0f --- /dev/null +++ b/.bazelrc @@ -0,0 +1,8 @@ +# Instead, you should run `bazel info bazel-bin` to find out where the outputs went. +build --symlink_prefix=dist/ + +# Display errors when tests fail +test --test_output=errors + +# Git output for build stamping +build --workspace_status_command=./tools/bazel_stamp_vars.sh diff --git a/modules/grpc-engine/BUILD.bazel b/modules/grpc-engine/BUILD.bazel new file mode 100644 index 000000000..dca4ae094 --- /dev/null +++ b/modules/grpc-engine/BUILD.bazel @@ -0,0 +1,58 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library", "ng_package", "ng_test_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "grpc-engine", + srcs = glob([ + "*.ts", + ]), + module_name = "@nguniversal/grpc-engine", + deps = [ + "//modules/grpc-engine/src:src", + ], +) + +ng_package( + name = "npm_package", + srcs = [ + ":grpc-engine.proto", + ":package.json", + ], + entry_point = "modules/grpc-engine/index.js", + readme_md = ":README.md", + tags = ["release"], + deps = [ + ":grpc-engine", + "@ngudeps//grpc", + ], +) + +ts_library( + name = "unit_test_lib", + srcs = glob([ + "spec/**/*.spec.ts", + ]), + testonly = 1, + deps = [ + ":grpc-engine", + "@angular//packages/platform-browser", + "@angular//packages/platform-server", + "@angular//packages/core", + "@angular//packages/core/testing", + "@ngudeps//domino", + "@ngudeps//grpc", + "@ngudeps//xhr2", + "@ngudeps//zone.js", + "@ngudeps//@grpc/proto-loader", + "@ngudeps//@types/jasmine", + ], +) + +jasmine_node_test( + name = "unit_test", + data = ["grpc-engine.proto"], + srcs = [ + ":unit_test_lib", + ], +) diff --git a/modules/grpc-engine/README.md b/modules/grpc-engine/README.md new file mode 100644 index 000000000..caf5b43b0 --- /dev/null +++ b/modules/grpc-engine/README.md @@ -0,0 +1,7 @@ +# Angular gRPC Engine + +This is a gRPC Engine for running Angular applications on the server for server side rendering + +## Usage + +To be added \ No newline at end of file diff --git a/modules/grpc-engine/grpc-engine.proto b/modules/grpc-engine/grpc-engine.proto new file mode 100644 index 000000000..37aa965b8 --- /dev/null +++ b/modules/grpc-engine/grpc-engine.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; +package grpcengine; + + +service SSR { + rpc render(RenderOptions) returns (RenderResponse) {} +} + +message RenderOptions { + int32 id = 1; + string document = 2; + string documentFilename = 3; +} + +message RenderResponse { + int32 id = 1; + string html = 2; + Error error = 3; +} + +message Error { + string message = 1; + string stack = 2; +} diff --git a/modules/grpc-engine/index.ts b/modules/grpc-engine/index.ts new file mode 100644 index 000000000..45965af3d --- /dev/null +++ b/modules/grpc-engine/index.ts @@ -0,0 +1,8 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +export * from './public_api'; diff --git a/modules/grpc-engine/package.json b/modules/grpc-engine/package.json new file mode 100644 index 000000000..e45c41b04 --- /dev/null +++ b/modules/grpc-engine/package.json @@ -0,0 +1,28 @@ +{ + "name": "@nguniversal/grpc-engine", + "version": "0.0.0-PLACEHOLDER", + "description": "gRPC engine for running server Angular applications", + "license": "MIT", + "keywords": [ + "grpc", + "ssr", + "universal" + ], + "peerDependencies": { + "@angular/common": "NG_VERSION", + "@angular/core": "NG_VERSION", + "@angular/platform-server": "NG_VERSION", + "grpc": "^1.11.3" + }, + "ng-update": { + "packageGroup": "NG_UPDATE_PACKAGE_GROUP" + }, + "repository": { + "type": "git", + "url": "https://github.com/angular/universal" + }, + "bugs": { + "url": "https://github.com/angular/universal/issues" + }, + "homepage": "https://github.com/angular/universal" +} diff --git a/modules/grpc-engine/public_api.ts b/modules/grpc-engine/public_api.ts new file mode 100644 index 000000000..ed3a32155 --- /dev/null +++ b/modules/grpc-engine/public_api.ts @@ -0,0 +1,8 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +export { startGRPCEngine } from './src/main'; diff --git a/modules/grpc-engine/spec/index.spec.ts b/modules/grpc-engine/spec/index.spec.ts new file mode 100644 index 000000000..5dac1f8fc --- /dev/null +++ b/modules/grpc-engine/spec/index.spec.ts @@ -0,0 +1,46 @@ +import { ServerModule } from '@angular/platform-server'; +import { NgModule, Component } from '@angular/core'; +import 'zone.js'; + +import { BrowserModule } from '@angular/platform-browser'; +import { startGRPCEngine } from '@nguniversal/grpc-engine'; +import { credentials, loadPackageDefinition } from 'grpc'; +import { loadSync } from '@grpc/proto-loader'; + +function createClient() { + const packageDefinition = loadSync('modules/grpc-engine/grpc-engine.proto', {}); + const grpcEngineProto = loadPackageDefinition(packageDefinition).grpcengine; + + const client = new grpcEngineProto.SSR('localhost:9090', credentials.createInsecure()); + return client; +} + +export function makeTestingModule(template: string, component?: any): any { + @Component({ + selector: 'root', + template: template + }) + class MockComponent {} + @NgModule({ + imports: [ServerModule, BrowserModule.withServerTransition({appId: 'mock'})], + declarations: [component || MockComponent], + bootstrap: [component || MockComponent] + }) + class MockServerModule {} + return MockServerModule; +} + +describe('test runner', () => { + it('should render a basic template', async (done) => { + const template = `some template: ${new Date()}`; + const appModule = makeTestingModule(template); + const server = await startGRPCEngine(appModule); + const client = createClient(); + + client.render({id: 1, document: ''}, async(_err: any, response: any) => { + expect(response).toContain(template); + await server.close(); + done(); + }); + }); +}); diff --git a/modules/grpc-engine/src/BUILD.bazel b/modules/grpc-engine/src/BUILD.bazel new file mode 100644 index 000000000..cfeb49804 --- /dev/null +++ b/modules/grpc-engine/src/BUILD.bazel @@ -0,0 +1,27 @@ +load("@build_bazel_rules_typescript//:defs.bzl", "ts_proto_library") +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library", "ng_package", "ng_test_library") +package(default_visibility = ["//visibility:public"]) + +# We get some error trying to use these: ReferenceError: define is not defined +# proto_library( +# name = "engine_proto", +# srcs = ["grpc-engine.proto"], +# ) + +# ts_proto_library( +# name = "engine_proto_ts", +# deps = [":engine_proto"], +# ) + +ts_library( + name = "src", + srcs = glob([ + "main.ts", + ]), + deps = [ + "@angular//packages/core", + "@ngudeps//grpc", + "@ngudeps//@grpc/proto-loader", + "//modules/common/engine", + ], +) diff --git a/modules/grpc-engine/src/main.ts b/modules/grpc-engine/src/main.ts new file mode 100644 index 000000000..68e7c0edd --- /dev/null +++ b/modules/grpc-engine/src/main.ts @@ -0,0 +1,76 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { + ɵCommonEngine as CommonEngine, + ɵRenderOptions as RenderOptions, +} from '@nguniversal/common/engine'; +import {NgModuleFactory, Type} from '@angular/core'; +import * as grpc from 'grpc'; +import * as protoLoader from '@grpc/proto-loader'; +import * as path from 'path'; + +// don't move this file without understanding the below reasoning +// +// we assume the dir structure between this file and grpc-engine.proto +// this is handled by including the file into unit tests with `data = []` +// for publishing we understand that: +// - fesm5, fesm2015 will all work +// - but esm5 and esm2015 will be broken +// if the structure of ng_package change it may break this +// +// also don't change the name of the file since users have to reference it by name +const GRPC_ENGINE_PROTO_FILENAME = 'grpc-engine.proto'; +const protoPath = path.join(__dirname, '..', GRPC_ENGINE_PROTO_FILENAME); +const packageDefinition = protoLoader.loadSync(protoPath, {}); +const grpcEngineProto = grpc.loadPackageDefinition(packageDefinition).grpcengine; + +export interface GRPCEngineServer { + close: () => void; +} + +export interface GRPCEngineRenderOptions extends RenderOptions { + id: number; +} + +export interface GRPCEngineResponse { + id: number; + html: string; +} + +export function startGRPCEngine( + moduleOrFactory: Type<{}> | NgModuleFactory<{}>, + host = '0.0.0.0', + port = 9090, + creds: grpc.ServerCredentials, +): Promise { + // needs to be a directory up so it lines up with deployment + return new Promise((resolve, _reject) => { + const engine = new CommonEngine(moduleOrFactory); + const server = new grpc.Server(); + + server.addProtoService(grpcEngineProto.SSR.service, { + render: async (call: any, callback: any) => { + const renderOptions = call.request as GRPCEngineRenderOptions; + try { + const html = await engine.render(renderOptions); + callback(null, {id: renderOptions.id, html}); + } catch (error) { + callback(null, {id: renderOptions.id, error}); + } + } + }); + // TODO(Toxicable): how to take credentials as input? + server.bind(`${host}:${port}`, creds); + server.start(); + + resolve({ + close: () => new Promise((res, _rej) => server.tryShutdown(() => res())) + }); + }); +} + diff --git a/package.json b/package.json index cc35469f0..18e60fb12 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,11 @@ "zone.js": "^0.8.26" }, "dependencies": { + "@grpc/grpc-js": "^0.3.2", + "@grpc/proto-loader": "^0.3.0", + "@types/ws": "^5.1.1", + "grpc": "^1.12.2", + "ws": "^5.1.1", "yarn": "^1.10.1" } } diff --git a/yarn.lock b/yarn.lock index be268d652..cd951e545 100644 --- a/yarn.lock +++ b/yarn.lock @@ -148,6 +148,77 @@ source-map-support "0.5.9" tsutils "2.27.2" +"@grpc/grpc-js@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-0.3.2.tgz#8adcf22154bfd4a0903296d6656420c2ff86e388" + integrity sha512-vvcC4EZwS2kzEuwe3zmExi20YM1tqO+L/xdpzInze0WnRfhwbssDfLtMfAyAPQaL2CD8dRZLCOVLbsSdF1KVjA== + dependencies: + lodash "^4.17.4" + semver "^5.5.0" + +"@grpc/proto-loader@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.3.0.tgz#c127d3859bff895f220453612ba04b923af0c584" + integrity sha512-9b8S/V+3W4Gv7G/JKSZ48zApgyYbfIR7mAC9XNnaSWme3zj57MIESu0ELzm9j5oxNIpFG8DgO00iJMIUZ5luqw== + dependencies: + "@types/lodash" "^4.14.104" + "@types/node" "^9.4.6" + lodash "^4.17.5" + protobufjs "^6.8.6" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + "@schematics/angular@^7.0.4", "@schematics/angular@^7.1.0": version "7.1.4" resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.1.4.tgz#cec4a5b793e54bd624018b6b5b4b917c467d22a5" @@ -230,6 +301,16 @@ version "14.0.1" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-14.0.1.tgz#739be8a8899a75631a3c9f15611e54bbab06c024" +"@types/lodash@^4.14.104": + version "4.14.119" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.119.tgz#be847e5f4bc3e35e46d041c394ead8b603ad8b39" + integrity sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw== + +"@types/long@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" + integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q== + "@types/mime-db@*": version "1.27.0" resolved "https://registry.yarnpkg.com/@types/mime-db/-/mime-db-1.27.0.tgz#9bc014a1fd1fdf47649c1a54c6dd7966b8284792" @@ -244,7 +325,7 @@ dependencies: "@types/mime-db" "*" -"@types/node@*": +"@types/node@*", "@types/node@^10.1.0": version "10.12.18" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" @@ -289,6 +370,14 @@ dependencies: "@types/node" "*" +"@types/ws@^5.1.1": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-5.1.2.tgz#f02d3b1cd46db7686734f3ce83bdf46c49decd64" + integrity sha512-NkTXUKTYdXdnPE2aUUbGOXE1XfMK527SCvU/9bj86kyFF6kZ9ZnOQ3mK5jADn98Y2vEUD/7wKDgZa7Qst2wYOg== + dependencies: + "@types/events" "*" + "@types/node" "*" + JSONStream@^1.0.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -2481,6 +2570,17 @@ graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" +grpc@^1.12.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.17.0.tgz#d7971dd39bd4eec90c69a048f7727795ab504876" + integrity sha512-5zb5ilwHlsiWfE2Abq/IN5SkHQ2zi4QF/u9Gewcw5DO3y+hGTtzZUiMK52MX3YZHAIRjqxDcO3fx0jLhPjT8Zw== + dependencies: + lodash.camelcase "^4.3.0" + lodash.clone "^4.5.0" + nan "^2.0.0" + node-pre-gyp "^0.12.0" + protobufjs "^5.0.3" + handlebars@^4.0.1, handlebars@^4.0.2: version "4.0.12" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" @@ -3481,6 +3581,16 @@ lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + +lodash.clone@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -3551,6 +3661,11 @@ loggly@^1.1.0: request "2.75.x" timespan "2.3.x" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + long@~3: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" @@ -3848,9 +3963,10 @@ ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" -nan@^2.9.2: +nan@^2.0.0, nan@^2.9.2: version "2.12.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== nanomatch@^1.2.9: version "1.2.13" @@ -3910,6 +4026,22 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + 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" + node-uuid@~1.4.7: version "1.4.8" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" @@ -4433,15 +4565,35 @@ promisify-call@^2.0.2: dependencies: with-callback "^1.0.2" -protobufjs@5.0.3: +protobufjs@5.0.3, protobufjs@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" + integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA== dependencies: ascli "~1" bytebuffer "~5" glob "^7.0.5" yargs "^3.10.0" +protobufjs@^6.8.6: + version "6.8.8" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" + integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + protractor@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.1.tgz#011a99e38df7aa45d22455b889ffbb13a6ce0bd9" @@ -6102,6 +6254,13 @@ wreck@14.x.x: boom "7.x.x" hoek "6.x.x" +ws@^5.1.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"