mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 02:54:21 +08:00
fix(@angular-devkit/build-angular): ERR_SSL_PROTOCOL_ERROR when using HTTPS reverse proxy
With this change we set the publicHost to `0.0.0.0:0`, when it's not provided.
This solved issues where previously the publicHost needed to be specified directly to get around `ERR_SSL_PROTOCOL_ERROR` error when proxing https -> http.
NB: this was also the behaviour in version 10 c252968225/packages/angular_devkit/build_angular/src/dev-server/index.ts (L170)
Closes #19403
This commit is contained in:
parent
ddd114cdfc
commit
f67c612393
@ -101,6 +101,7 @@
|
||||
"@types/express": "^4.16.0",
|
||||
"@types/find-cache-dir": "^3.0.0",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
"@types/inquirer": "^7.3.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/karma": "^5.0.0",
|
||||
@ -153,6 +154,7 @@
|
||||
"gh-got": "^9.0.0",
|
||||
"git-raw-commits": "^2.0.0",
|
||||
"glob": "7.1.6",
|
||||
"http-proxy": "^1.18.1",
|
||||
"husky": "^4.0.10",
|
||||
"inquirer": "7.3.3",
|
||||
"jasmine": "^3.3.1",
|
||||
|
@ -282,6 +282,8 @@ LARGE_SPECS = {
|
||||
"@npm//@types/node-fetch",
|
||||
"@npm//express",
|
||||
"@npm//node-fetch",
|
||||
"@npm//@types/http-proxy",
|
||||
"@npm//http-proxy",
|
||||
"@npm//puppeteer",
|
||||
],
|
||||
},
|
||||
|
@ -0,0 +1,249 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. 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
|
||||
*/
|
||||
// tslint:disable: no-implicit-dependencies
|
||||
import { Architect, BuilderRun } from '@angular-devkit/architect';
|
||||
import { tags } from '@angular-devkit/core';
|
||||
import { createProxyServer } from 'http-proxy';
|
||||
import { HTTPResponse } from 'puppeteer/lib/cjs/puppeteer/api-docs-entry';
|
||||
import { Browser } from 'puppeteer/lib/cjs/puppeteer/common/Browser';
|
||||
import { Page } from 'puppeteer/lib/cjs/puppeteer/common/Page';
|
||||
import puppeteer from 'puppeteer/lib/cjs/puppeteer/node';
|
||||
import { debounceTime, switchMap, take } from 'rxjs/operators';
|
||||
import { createArchitect, host } from '../test-utils';
|
||||
|
||||
// tslint:disable-next-line: no-any
|
||||
declare const document: any;
|
||||
|
||||
interface ProxyInstance {
|
||||
server: typeof createProxyServer extends () => infer R ? R : never;
|
||||
url: string;
|
||||
}
|
||||
|
||||
let proxyPort = 9100;
|
||||
function createProxy(target: string, secure: boolean): ProxyInstance {
|
||||
proxyPort++;
|
||||
|
||||
const server = createProxyServer({
|
||||
ws: true,
|
||||
target,
|
||||
secure,
|
||||
ssl: secure && {
|
||||
key: tags.stripIndents`
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt
|
||||
CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK
|
||||
dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF
|
||||
gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k
|
||||
9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy
|
||||
7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ
|
||||
3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5
|
||||
ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU
|
||||
faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3
|
||||
/SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ
|
||||
BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/
|
||||
Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6
|
||||
XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV
|
||||
6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj
|
||||
9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U
|
||||
fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P
|
||||
nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz
|
||||
TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV
|
||||
HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY
|
||||
/16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX
|
||||
JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3
|
||||
zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ
|
||||
iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml
|
||||
amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6
|
||||
Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW
|
||||
QyvMqmN1kGy20SZbQDD/fLfqBQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`,
|
||||
cert: tags.stripIndents`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1
|
||||
J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM
|
||||
ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU
|
||||
E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI
|
||||
NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS
|
||||
tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb
|
||||
3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw
|
||||
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72
|
||||
6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg
|
||||
LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb
|
||||
hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+
|
||||
Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU
|
||||
DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I
|
||||
7Q==
|
||||
-----END CERTIFICATE-----
|
||||
`,
|
||||
},
|
||||
})
|
||||
.listen(proxyPort);
|
||||
|
||||
return {
|
||||
server,
|
||||
url: `${secure ? 'https' : 'http'}://localhost:${proxyPort}`,
|
||||
};
|
||||
}
|
||||
|
||||
async function goToPageAndWaitForSockJs(page: Page, url: string): Promise<void> {
|
||||
const socksRequest = `${url.endsWith('/') ? url : url + '/'}sockjs-node/info?t=`;
|
||||
|
||||
await Promise.all([
|
||||
page.waitForResponse((r: HTTPResponse) => r.url().startsWith(socksRequest) && r.status() === 200),
|
||||
page.goto(url),
|
||||
]);
|
||||
}
|
||||
|
||||
describe('Dev Server Builder live-reload', () => {
|
||||
const target = { project: 'app', target: 'serve' };
|
||||
const overrides = { hmr: false, watch: true, port: 0, liveReload: true };
|
||||
let architect: Architect;
|
||||
let browser: Browser;
|
||||
let page: Page;
|
||||
let runs: BuilderRun[];
|
||||
let proxy: ProxyInstance | undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
browser = await puppeteer.launch({
|
||||
// MacOSX users need to set the local binary manually because Chrome has lib files with
|
||||
// spaces in them which Bazel does not support in runfiles
|
||||
// See: https://github.com/angular/angular-cli/pull/17624
|
||||
// tslint:disable-next-line: max-line-length
|
||||
// executablePath: '/Users/<USERNAME>/git/angular-cli/node_modules/puppeteer/.local-chromium/mac-809590/chrome-mac/Chromium.app/Contents/MacOS/Chromium',
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-gpu',
|
||||
'--ignore-certificate-errors',
|
||||
'--ignore-urlfetcher-cert-requests',
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await host.initialize().toPromise();
|
||||
architect = (await createArchitect(host.root())).architect;
|
||||
|
||||
host.writeMultipleFiles({
|
||||
'src/app/app.component.html': `
|
||||
<p>{{title}}</p>
|
||||
`,
|
||||
});
|
||||
|
||||
runs = [];
|
||||
page = await browser.newPage();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
proxy?.server.close();
|
||||
proxy = undefined;
|
||||
await host.restore().toPromise();
|
||||
await page.close();
|
||||
await Promise.all(runs.map(r => r.stop()));
|
||||
});
|
||||
|
||||
it('works without proxy', async () => {
|
||||
const run = await architect.scheduleTarget(target, overrides);
|
||||
runs.push(run);
|
||||
|
||||
let buildCount = 0;
|
||||
await run.output
|
||||
.pipe(
|
||||
debounceTime(1000),
|
||||
switchMap(async buildEvent => {
|
||||
expect(buildEvent.success).toBe(true);
|
||||
const url = buildEvent.baseUrl as string;
|
||||
switch (buildCount) {
|
||||
case 0:
|
||||
await goToPageAndWaitForSockJs(page, url);
|
||||
host.replaceInFile('src/app/app.component.ts', `'app'`, `'app-live-reload'`);
|
||||
break;
|
||||
case 1:
|
||||
const innerText = await page.evaluate(() => document.querySelector('p').innerText);
|
||||
expect(innerText).toBe('app-live-reload');
|
||||
break;
|
||||
}
|
||||
|
||||
buildCount++;
|
||||
}),
|
||||
take(2),
|
||||
)
|
||||
.toPromise();
|
||||
}, 30000);
|
||||
|
||||
it('works without http -> http proxy', async () => {
|
||||
const run = await architect.scheduleTarget(target, overrides);
|
||||
runs.push(run);
|
||||
|
||||
let proxy: ProxyInstance | undefined;
|
||||
let buildCount = 0;
|
||||
await run.output
|
||||
.pipe(
|
||||
debounceTime(1000),
|
||||
switchMap(async buildEvent => {
|
||||
expect(buildEvent.success).toBe(true);
|
||||
const url = buildEvent.baseUrl as string;
|
||||
switch (buildCount) {
|
||||
case 0:
|
||||
proxy = createProxy(url, false);
|
||||
await goToPageAndWaitForSockJs(page, proxy.url);
|
||||
host.replaceInFile('src/app/app.component.ts', `'app'`, `'app-live-reload'`);
|
||||
break;
|
||||
case 1:
|
||||
const innerText = await page.evaluate(() => document.querySelector('p').innerText);
|
||||
expect(innerText).toBe('app-live-reload');
|
||||
break;
|
||||
}
|
||||
|
||||
buildCount++;
|
||||
}),
|
||||
take(2),
|
||||
)
|
||||
.toPromise();
|
||||
}, 30000);
|
||||
|
||||
it('works without https -> http proxy', async () => {
|
||||
const run = await architect.scheduleTarget(target, overrides);
|
||||
runs.push(run);
|
||||
|
||||
let proxy: ProxyInstance | undefined;
|
||||
let buildCount = 0;
|
||||
await run.output
|
||||
.pipe(
|
||||
debounceTime(1000),
|
||||
switchMap(async buildEvent => {
|
||||
expect(buildEvent.success).toBe(true);
|
||||
const url = buildEvent.baseUrl as string;
|
||||
switch (buildCount) {
|
||||
case 0:
|
||||
proxy = createProxy(url, true);
|
||||
await goToPageAndWaitForSockJs(page, proxy.url);
|
||||
host.replaceInFile('src/app/app.component.ts', `'app'`, `'app-live-reload'`);
|
||||
break;
|
||||
case 1:
|
||||
const innerText = await page.evaluate(() => document.querySelector('p').innerText);
|
||||
expect(innerText).toBe('app-live-reload');
|
||||
break;
|
||||
}
|
||||
|
||||
buildCount++;
|
||||
}),
|
||||
take(2),
|
||||
)
|
||||
.toPromise();
|
||||
}, 30000);
|
||||
});
|
@ -56,6 +56,8 @@ export function getDevServerConfig(
|
||||
|
||||
const parsedHost = url.parse(publicHost);
|
||||
publicHost = parsedHost.host;
|
||||
} else {
|
||||
publicHost = '0.0.0.0:0';
|
||||
}
|
||||
|
||||
if (!watch) {
|
||||
|
@ -1,172 +0,0 @@
|
||||
export default function temporarilyDisabledTest() { return Promise.resolve(); }
|
||||
// import * as os from 'os';
|
||||
// import * as _ from 'lodash';
|
||||
// import * as express from 'express';
|
||||
// import * as http from 'http';
|
||||
|
||||
// import {appendToFile, writeMultipleFiles, writeFile} from '../../utils/fs';
|
||||
// import {
|
||||
// killAllProcesses,
|
||||
// execAndWaitForOutputToMatch,
|
||||
// waitForAnyProcessOutputToMatch
|
||||
// } from '../../utils/process';
|
||||
// import { wait } from '../../utils/utils';
|
||||
|
||||
|
||||
// export default function () {
|
||||
// const protractorGoodRegEx = /Jasmine started/;
|
||||
// const webpackGoodRegEx = / Compiled successfully./;
|
||||
|
||||
// // Create an express api for the Angular app to call.
|
||||
// const app = express();
|
||||
// const server = http.createServer(app);
|
||||
// let liveReloadCount = 0;
|
||||
// function resetApiVars() {
|
||||
// liveReloadCount = 0;
|
||||
// }
|
||||
|
||||
// server.listen(0);
|
||||
// app.set('port', server.address().port);
|
||||
|
||||
// const firstLocalIp = _(os.networkInterfaces())
|
||||
// .values()
|
||||
// .flatten()
|
||||
// .filter({ family: 'IPv4', internal: false })
|
||||
// .map('address')
|
||||
// .first();
|
||||
// const publicHost = `${firstLocalIp}:4200`;
|
||||
|
||||
// const apiUrl = `http://localhost:${server.address().port}`;
|
||||
|
||||
// // This endpoint will be pinged by the main app on each reload.
|
||||
// app.get('/live-reload-count', _ => liveReloadCount++);
|
||||
|
||||
// const proxyConfigFile = 'proxy.config.json';
|
||||
// const proxyConfig = {
|
||||
// '/live-reload-count': {
|
||||
// target: apiUrl
|
||||
// }
|
||||
// };
|
||||
|
||||
// return Promise.resolve()
|
||||
// .then(_ => writeMultipleFiles({
|
||||
// 'src/app/app.module.ts': `
|
||||
// import { BrowserModule } from '@angular/platform-browser';
|
||||
// import { NgModule } from '@angular/core';
|
||||
// import { FormsModule } from '@angular/forms';
|
||||
// import { HttpModule } from '@angular/http';
|
||||
// import { AppComponent } from './app.component';
|
||||
// @NgModule({
|
||||
// declarations: [
|
||||
// AppComponent
|
||||
// ],
|
||||
// imports: [
|
||||
// BrowserModule,
|
||||
// FormsModule,
|
||||
// HttpModule
|
||||
// ],
|
||||
// providers: [],
|
||||
// bootstrap: [AppComponent]
|
||||
// })
|
||||
// export class AppModule { }
|
||||
// `,
|
||||
// // e2e test that just opens the page and waits, so that the app runs.
|
||||
// './e2e/app.e2e-spec.ts': `
|
||||
// import { browser } from 'protractor';
|
||||
|
||||
// describe('master-project App', function() {
|
||||
// it('should wait', _ => {
|
||||
// browser.get('/');
|
||||
// browser.sleep(30000);
|
||||
// });
|
||||
// });
|
||||
// `,
|
||||
// // App that calls the express server once.
|
||||
// './src/app/app.component.ts': `
|
||||
// import { Component } from '@angular/core';
|
||||
// import { Http } from '@angular/http';
|
||||
|
||||
// @Component({
|
||||
// selector: 'app-root',
|
||||
// template: '<h1>Live reload test</h1>'
|
||||
// })
|
||||
// export class AppComponent {
|
||||
// constructor(private http: Http) {
|
||||
// http.get('${apiUrl + '/live-reload-count'}').subscribe(res => null);
|
||||
// }
|
||||
// }
|
||||
// `
|
||||
// }))
|
||||
// .then(_ => execAndWaitForOutputToMatch(
|
||||
// 'ng',
|
||||
// ['e2e', '--watch', '--live-reload'],
|
||||
// protractorGoodRegEx
|
||||
// ))
|
||||
// // Let app run.
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => appendToFile('src/main.ts', 'console.log(1);'))
|
||||
// .then(_ => waitForAnyProcessOutputToMatch(webpackGoodRegEx, 10000))
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => {
|
||||
// if (liveReloadCount != 2) {
|
||||
// throw new Error(
|
||||
// `Expected API to have been called 2 times but it was called ${liveReloadCount} times.`
|
||||
// );
|
||||
// }
|
||||
// })
|
||||
// .then(_ => killAllProcesses(), (err) => { killAllProcesses(); throw err; })
|
||||
// .then(_ => resetApiVars())
|
||||
// // Serve with live reload off should call api only once.
|
||||
// .then(_ => execAndWaitForOutputToMatch(
|
||||
// 'ng',
|
||||
// ['e2e', '--watch', '--no-live-reload'],
|
||||
// protractorGoodRegEx
|
||||
// ))
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => appendToFile('src/main.ts', 'console.log(1);'))
|
||||
// .then(_ => waitForAnyProcessOutputToMatch(webpackGoodRegEx, 10000))
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => {
|
||||
// if (liveReloadCount != 1) {
|
||||
// throw new Error(
|
||||
// `Expected API to have been called 1 time but it was called ${liveReloadCount} times.`
|
||||
// );
|
||||
// }
|
||||
// })
|
||||
// .then(_ => killAllProcesses(), (err) => { killAllProcesses(); throw err; })
|
||||
// .then(_ => resetApiVars())
|
||||
// // Serve with live reload client set to api should call api.
|
||||
// .then(() => writeFile(proxyConfigFile, JSON.stringify(proxyConfig, null, 2)))
|
||||
// // Update the component to call the webserver
|
||||
// .then(() => writeFile('./src/app/app.component.ts',
|
||||
// `
|
||||
// import { Component } from '@angular/core';
|
||||
// import { Http } from '@angular/http';
|
||||
// @Component({
|
||||
// selector: 'app-root',
|
||||
// template: '<h1>Live reload test</h1>'
|
||||
// })
|
||||
// export class AppComponent {
|
||||
// constructor(private http: Http) {
|
||||
// http.get('http://${publicHost + '/live-reload-count'}').subscribe(res => null);
|
||||
// }
|
||||
// }`))
|
||||
// .then(_ => execAndWaitForOutputToMatch(
|
||||
// 'ng',
|
||||
// ['e2e', '--watch', '--host=0.0.0.0', '--port=4200', `--public-host=${publicHost}`, '--proxy', proxyConfigFile],
|
||||
// protractorGoodRegEx
|
||||
// ))
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => appendToFile('src/main.ts', 'console.log(1);'))
|
||||
// .then(_ => waitForAnyProcessOutputToMatch(webpackGoodRegEx, 10000))
|
||||
// .then(_ => wait(2000))
|
||||
// .then(_ => {
|
||||
// if (liveReloadCount != 2) {
|
||||
// throw new Error(
|
||||
// `Expected API to have been called 2 times but it was called ${liveReloadCount} times.`
|
||||
// );
|
||||
// }
|
||||
// })
|
||||
// .then(_ => killAllProcesses(), (err) => { killAllProcesses(); throw err; })
|
||||
// .then(_ => server.close(), (err) => { server.close(); throw err; });
|
||||
// }
|
@ -1558,7 +1558,7 @@
|
||||
"@types/http-proxy" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/http-proxy@*":
|
||||
"@types/http-proxy@*", "@types/http-proxy@^1.17.4":
|
||||
version "1.17.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b"
|
||||
integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==
|
||||
|
Loading…
x
Reference in New Issue
Block a user