@lwrjs/dev-proxy-server 0.11.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +10 -0
- package/README.md +76 -0
- package/build/cjs/index.cjs +70 -0
- package/build/cjs/middleware.cjs +77 -0
- package/build/cjs/proxy-server.cjs +57 -0
- package/build/es/index.d.ts +19 -0
- package/build/es/index.js +58 -0
- package/build/es/middleware.d.ts +15 -0
- package/build/es/middleware.js +68 -0
- package/build/es/proxy-server.d.ts +24 -0
- package/build/es/proxy-server.js +33 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
MIT LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020, Salesforce.com, Inc.
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
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:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
|
|
10
|
+
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# LWR Development Proxy Server
|
|
2
|
+
|
|
3
|
+
The LWR Development Proxy Server enables LWR applications to reference resources hosted outside of the LWR runtime.
|
|
4
|
+
|
|
5
|
+
```ascii
|
|
6
|
+
┌──────────────┐
|
|
7
|
+
┌────────┐ │ │
|
|
8
|
+
│ │ │ │
|
|
9
|
+
│ │ │ lwr runtime │
|
|
10
|
+
https://example.com/home │ │─────────────────────────────▶│ │
|
|
11
|
+
──────────────────────────────▶│ site │ /home │ │
|
|
12
|
+
/1/bundle/.../bundle_lwc.js │ proxy │ /1/bundle/.../bundle_lwc.js└──────────────┘
|
|
13
|
+
/1/asset/.../global.css │ │ /1/asset/.../global.css
|
|
14
|
+
/content/.../logo-salesforce.svg │ │ ┌──────────────┐
|
|
15
|
+
│ │ │ │
|
|
16
|
+
│ │────────────────────────────────────▶│ content │
|
|
17
|
+
│ │ /content/.../logo-salesforce.svg │ origin │
|
|
18
|
+
└────────┘ │ │
|
|
19
|
+
│ │
|
|
20
|
+
└──────────────┘
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
In production deployments the proxying of distrbuted resources is typically provided by a dedicated service (e.g. Cloudfront, Cloudflare, NginX, etc), seperate from the origin application/UI services.
|
|
24
|
+
|
|
25
|
+
For local runtime scenarios, the LWR Development Proxy Server provides a simple and integrated local site proxy that can be used when developing, previewing or debugging the site or its built distribution.
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
To configure the Development Proxy Server add another proxy entry to the `_proxy` runtime configuration file in your projects `config` directory.
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
/content https://c1.sfdcstatic.com/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Each entry of the `_proxy` configuration includes the base `path` of the requests to be proxied to their associated origin host.
|
|
36
|
+
|
|
37
|
+
## LWR CLI Command support
|
|
38
|
+
|
|
39
|
+
The Development Proxy Server is integrated into the Lightning Web Runtime CLI commands -- `lwr dev`, `lwr build` and `lwr preview`.
|
|
40
|
+
|
|
41
|
+
The Development Proxy Server is only started with a site containing a [proxy configuration](#configuration).
|
|
42
|
+
|
|
43
|
+
### Dev
|
|
44
|
+
|
|
45
|
+
In `dev` mode, the CLI detects the existence of [proxy configuration](#configuration) in your source `config` directory and starts the local proxy server instance alongside the runtime.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
$ lwr dev
|
|
49
|
+
Running LWR Proxy at: http://localhost:3000
|
|
50
|
+
Running LWR at: http://localhost:3001 | mode: dev
|
|
51
|
+
Application site is available at: http://localhost:3000
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Build
|
|
55
|
+
|
|
56
|
+
When building a site with `lwr build`, the CLI stages any source [proxy configuration](#configuration) into the built distribution alongside the other site runtime resources.
|
|
57
|
+
|
|
58
|
+
### Preview
|
|
59
|
+
|
|
60
|
+
Like [Dev](#dev), previewing a site containing a [proxy configuration](#configuration) starts the local proxy server instance alongside the application runtime.
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
$ $ lwr preview
|
|
64
|
+
Running LWR Proxy at: http://localhost:3000
|
|
65
|
+
Running LWR at: http://localhost:3001 | mode: prod-compat
|
|
66
|
+
Application site is available at: http://localhost:3000
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The development proxy server is also enabled for previewing sites built for a specific target (e.g. `mrt`).
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
$ lwr preview --target=mrt --buildDir mrt-preview
|
|
73
|
+
Running LWR Proxy at: http://localhost:3000
|
|
74
|
+
LWR services have been started on: http://localhost:3000
|
|
75
|
+
Starting the DevServer on http://localhost:3001
|
|
76
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/dev-proxy-server/src/index.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
DEFAULT_PROXY_PORT: () => DEFAULT_PROXY_PORT,
|
|
28
|
+
createProxyServer: () => createProxyServer,
|
|
29
|
+
findProxyConfiguration: () => findProxyConfiguration
|
|
30
|
+
});
|
|
31
|
+
var import_fs = __toModule(require("fs"));
|
|
32
|
+
var import_path = __toModule(require("path"));
|
|
33
|
+
var import_proxy_server = __toModule(require("./proxy-server.cjs"));
|
|
34
|
+
var DEFAULT_PROXY_PORT = 4e3;
|
|
35
|
+
function createProxyServer(config) {
|
|
36
|
+
return new import_proxy_server.LwrProxyServer(config);
|
|
37
|
+
}
|
|
38
|
+
function findProxyConfiguration(rootDir, buildDir) {
|
|
39
|
+
const PROXY_CONFIG_ROOT = import_path.default.join("config", "_proxy");
|
|
40
|
+
if (buildDir) {
|
|
41
|
+
const buildProxyConfigFile = import_path.default.join(rootDir, buildDir, PROXY_CONFIG_ROOT);
|
|
42
|
+
if (import_fs.default.existsSync(buildProxyConfigFile)) {
|
|
43
|
+
return readAndProcessProxyConfiguration(buildProxyConfigFile);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const proxyConfigFile = import_path.default.join(rootDir, PROXY_CONFIG_ROOT);
|
|
47
|
+
if (import_fs.default.existsSync(proxyConfigFile)) {
|
|
48
|
+
return readAndProcessProxyConfiguration(proxyConfigFile);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
function readAndProcessProxyConfiguration(proxyConfigFile) {
|
|
53
|
+
const entries = import_fs.default.readFileSync(proxyConfigFile).toString().split("\n");
|
|
54
|
+
const proxyConfigs = entries.map((entry, idx) => {
|
|
55
|
+
const config = entry.split(" ");
|
|
56
|
+
if (config.length !== 2) {
|
|
57
|
+
throw new Error(`malformed proxy configuration at index ${idx} - missing configuration columns`);
|
|
58
|
+
}
|
|
59
|
+
if (!config[0].startsWith("/")) {
|
|
60
|
+
throw new Error(`malformed proxy configuration at index ${idx} - proxy path, must start with /`);
|
|
61
|
+
}
|
|
62
|
+
if (!config[1].match(/^([a-z][a-z0-9+\-.]*):\/\//)) {
|
|
63
|
+
throw new Error(`malformed proxy configuration at index ${idx} - proxy origin, must start with http[s]://`);
|
|
64
|
+
}
|
|
65
|
+
return config;
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
proxyConfigs
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/dev-proxy-server/src/middleware.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
addLocalProxyMiddleware: () => addLocalProxyMiddleware,
|
|
28
|
+
addRemoteProxyMiddleware: () => addRemoteProxyMiddleware
|
|
29
|
+
});
|
|
30
|
+
var import_http_proxy_middleware = __toModule(require("http-proxy-middleware"));
|
|
31
|
+
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
32
|
+
var HOST = "host";
|
|
33
|
+
var ProxyLogLevels;
|
|
34
|
+
(function(ProxyLogLevels2) {
|
|
35
|
+
ProxyLogLevels2["Debug"] = "debug";
|
|
36
|
+
ProxyLogLevels2["Info"] = "info";
|
|
37
|
+
ProxyLogLevels2["Warn"] = "warn";
|
|
38
|
+
ProxyLogLevels2["Error"] = "error";
|
|
39
|
+
ProxyLogLevels2["Silent"] = "silent";
|
|
40
|
+
})(ProxyLogLevels || (ProxyLogLevels = {}));
|
|
41
|
+
function addLocalProxyMiddleware(app, localHost) {
|
|
42
|
+
app.use("/", (0, import_http_proxy_middleware.default)({target: localHost, changeOrigin: true}));
|
|
43
|
+
}
|
|
44
|
+
function addRemoteProxyMiddleware(app, proxyConfig) {
|
|
45
|
+
const {proxyConfigs} = proxyConfig;
|
|
46
|
+
for (const entry of proxyConfigs) {
|
|
47
|
+
const [path, target] = entry;
|
|
48
|
+
const targetHost = target.replace(/^([a-z][a-z0-9+\-.]*):\/\//, "");
|
|
49
|
+
app.use(path, (0, import_http_proxy_middleware.default)({
|
|
50
|
+
target,
|
|
51
|
+
logLevel: resolveLogLevel(import_diagnostics.logger.currentLevel),
|
|
52
|
+
logProvider: () => {
|
|
53
|
+
return import_diagnostics.logger;
|
|
54
|
+
},
|
|
55
|
+
followRedirects: false,
|
|
56
|
+
changeOrigin: true,
|
|
57
|
+
onProxyReq: (proxyRequest, incomingRequest) => {
|
|
58
|
+
const hostHeader = incomingRequest.headers.host;
|
|
59
|
+
if (hostHeader !== target) {
|
|
60
|
+
proxyRequest.setHeader(HOST, targetHost);
|
|
61
|
+
}
|
|
62
|
+
proxyRequest.setHeader("Forwarded", `host=${hostHeader}`);
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function resolveLogLevel(currentLevel) {
|
|
68
|
+
if (currentLevel === import_diagnostics.VERBOSE || currentLevel === import_diagnostics.DEBUG)
|
|
69
|
+
return ProxyLogLevels.Debug;
|
|
70
|
+
if (currentLevel === import_diagnostics.INFO)
|
|
71
|
+
return ProxyLogLevels.Info;
|
|
72
|
+
if (currentLevel === import_diagnostics.ERROR)
|
|
73
|
+
return ProxyLogLevels.Info;
|
|
74
|
+
if (currentLevel === import_diagnostics.WARN)
|
|
75
|
+
return ProxyLogLevels.Info;
|
|
76
|
+
return ProxyLogLevels.Silent;
|
|
77
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/dev-proxy-server/src/proxy-server.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
LwrProxyServer: () => LwrProxyServer
|
|
28
|
+
});
|
|
29
|
+
var import_express = __toModule(require("express"));
|
|
30
|
+
var import_middleware = __toModule(require("./middleware.cjs"));
|
|
31
|
+
var LwrProxyServer = class {
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.proxyServer = (0, import_express.default)();
|
|
34
|
+
this.config = config;
|
|
35
|
+
(0, import_middleware.addRemoteProxyMiddleware)(this.proxyServer, this.config);
|
|
36
|
+
(0, import_middleware.addLocalProxyMiddleware)(this.proxyServer, this.config.defaultHost);
|
|
37
|
+
}
|
|
38
|
+
async listen(callback) {
|
|
39
|
+
const {proxyServer, config} = this;
|
|
40
|
+
const {port} = config;
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const server = proxyServer.listen(port, async () => {
|
|
43
|
+
const opts = {port};
|
|
44
|
+
callback?.(opts);
|
|
45
|
+
resolve(opts);
|
|
46
|
+
});
|
|
47
|
+
const handleError = (err) => {
|
|
48
|
+
server.off("error", handleError);
|
|
49
|
+
if (err.code === "EADDRINUSE") {
|
|
50
|
+
err = new Error(`Port ${port} is already in use.`);
|
|
51
|
+
}
|
|
52
|
+
reject(err);
|
|
53
|
+
};
|
|
54
|
+
server.on("error", handleError);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LwrProxyServerConfig, ProxyConfiguration } from './proxy-server';
|
|
2
|
+
import { LwrProxyServer } from './proxy-server.js';
|
|
3
|
+
export declare const DEFAULT_PROXY_PORT = 4000;
|
|
4
|
+
/**
|
|
5
|
+
* Creates an Development Proxy Server using the provided `LwrProxyServerConfig` configuration.
|
|
6
|
+
* @param config The configuration for the proxy
|
|
7
|
+
* @returns LwrProxyServer instance
|
|
8
|
+
*/
|
|
9
|
+
export declare function createProxyServer(config: LwrProxyServerConfig): LwrProxyServer;
|
|
10
|
+
/**
|
|
11
|
+
* Searches for a `_proxy` configuration resource using the following search logic:
|
|
12
|
+
* - ${rootDir}/${buildDir}/config/_proxy
|
|
13
|
+
* - ${rootDir}/config/_proxy
|
|
14
|
+
* @param rootDir The root directory of the project
|
|
15
|
+
* @param buildDir The built distribution directory/
|
|
16
|
+
* @returns The found ProxyConfiguration object or undefined if no _proxy object could be found.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findProxyConfiguration(rootDir: string, buildDir?: string): ProxyConfiguration | undefined;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { LwrProxyServer } from './proxy-server.js';
|
|
4
|
+
// Default Proxy server port
|
|
5
|
+
export const DEFAULT_PROXY_PORT = 4000;
|
|
6
|
+
/**
|
|
7
|
+
* Creates an Development Proxy Server using the provided `LwrProxyServerConfig` configuration.
|
|
8
|
+
* @param config The configuration for the proxy
|
|
9
|
+
* @returns LwrProxyServer instance
|
|
10
|
+
*/
|
|
11
|
+
export function createProxyServer(config) {
|
|
12
|
+
return new LwrProxyServer(config);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Searches for a `_proxy` configuration resource using the following search logic:
|
|
16
|
+
* - ${rootDir}/${buildDir}/config/_proxy
|
|
17
|
+
* - ${rootDir}/config/_proxy
|
|
18
|
+
* @param rootDir The root directory of the project
|
|
19
|
+
* @param buildDir The built distribution directory/
|
|
20
|
+
* @returns The found ProxyConfiguration object or undefined if no _proxy object could be found.
|
|
21
|
+
*/
|
|
22
|
+
export function findProxyConfiguration(rootDir, buildDir) {
|
|
23
|
+
const PROXY_CONFIG_ROOT = path.join('config', '_proxy');
|
|
24
|
+
if (buildDir) {
|
|
25
|
+
// check the built/dist if its provided and exists
|
|
26
|
+
const buildProxyConfigFile = path.join(rootDir, buildDir, PROXY_CONFIG_ROOT);
|
|
27
|
+
if (fs.existsSync(buildProxyConfigFile)) {
|
|
28
|
+
// read, parse, and return the configuration resource
|
|
29
|
+
return readAndProcessProxyConfiguration(buildProxyConfigFile);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const proxyConfigFile = path.join(rootDir, PROXY_CONFIG_ROOT);
|
|
33
|
+
if (fs.existsSync(proxyConfigFile)) {
|
|
34
|
+
// read, parse, and return the configuration resource
|
|
35
|
+
return readAndProcessProxyConfiguration(proxyConfigFile);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
function readAndProcessProxyConfiguration(proxyConfigFile) {
|
|
40
|
+
const entries = fs.readFileSync(proxyConfigFile).toString().split('\n');
|
|
41
|
+
const proxyConfigs = entries.map((entry, idx) => {
|
|
42
|
+
const config = entry.split(' ');
|
|
43
|
+
if (config.length !== 2) {
|
|
44
|
+
throw new Error(`malformed proxy configuration at index ${idx} - missing configuration columns`);
|
|
45
|
+
}
|
|
46
|
+
if (!config[0].startsWith('/')) {
|
|
47
|
+
throw new Error(`malformed proxy configuration at index ${idx} - proxy path, must start with /`);
|
|
48
|
+
}
|
|
49
|
+
if (!config[1].match(/^([a-z][a-z0-9+\-.]*):\/\//)) {
|
|
50
|
+
throw new Error(`malformed proxy configuration at index ${idx} - proxy origin, must start with http[s]://`);
|
|
51
|
+
}
|
|
52
|
+
return config;
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
proxyConfigs,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Application as ExpressApp } from 'express';
|
|
2
|
+
import type { ProxyConfiguration } from './proxy-server.js';
|
|
3
|
+
/**
|
|
4
|
+
* The Proxy middleware responsible for proxying all other requests not configured to external systems.
|
|
5
|
+
* @param app
|
|
6
|
+
* @param localHost
|
|
7
|
+
*/
|
|
8
|
+
export declare function addLocalProxyMiddleware(app: ExpressApp, localHost: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* The Proxy middleware responsible for proxying requests to a configured remote origin.
|
|
11
|
+
* @param app
|
|
12
|
+
* @param proxyConfig
|
|
13
|
+
*/
|
|
14
|
+
export declare function addRemoteProxyMiddleware(app: ExpressApp, proxyConfig: ProxyConfiguration): void;
|
|
15
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import proxy from 'http-proxy-middleware';
|
|
2
|
+
import { logger, WARN, INFO, VERBOSE, DEBUG, ERROR } from '@lwrjs/diagnostics';
|
|
3
|
+
// Header constants
|
|
4
|
+
const HOST = 'host';
|
|
5
|
+
// Log levels enumeration
|
|
6
|
+
var ProxyLogLevels;
|
|
7
|
+
(function (ProxyLogLevels) {
|
|
8
|
+
ProxyLogLevels["Debug"] = "debug";
|
|
9
|
+
ProxyLogLevels["Info"] = "info";
|
|
10
|
+
ProxyLogLevels["Warn"] = "warn";
|
|
11
|
+
ProxyLogLevels["Error"] = "error";
|
|
12
|
+
ProxyLogLevels["Silent"] = "silent";
|
|
13
|
+
})(ProxyLogLevels || (ProxyLogLevels = {}));
|
|
14
|
+
/**
|
|
15
|
+
* The Proxy middleware responsible for proxying all other requests not configured to external systems.
|
|
16
|
+
* @param app
|
|
17
|
+
* @param localHost
|
|
18
|
+
*/
|
|
19
|
+
export function addLocalProxyMiddleware(app, localHost) {
|
|
20
|
+
app.use('/', proxy({ target: localHost, changeOrigin: true }));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The Proxy middleware responsible for proxying requests to a configured remote origin.
|
|
24
|
+
* @param app
|
|
25
|
+
* @param proxyConfig
|
|
26
|
+
*/
|
|
27
|
+
export function addRemoteProxyMiddleware(app, proxyConfig) {
|
|
28
|
+
const { proxyConfigs } = proxyConfig;
|
|
29
|
+
for (const entry of proxyConfigs) {
|
|
30
|
+
const [path, target] = entry;
|
|
31
|
+
// remove the scheme from the proxyConfig host.
|
|
32
|
+
const targetHost = target.replace(/^([a-z][a-z0-9+\-.]*):\/\//, '');
|
|
33
|
+
app.use(path, proxy({
|
|
34
|
+
target,
|
|
35
|
+
logLevel: resolveLogLevel(logger.currentLevel),
|
|
36
|
+
logProvider: () => {
|
|
37
|
+
return logger;
|
|
38
|
+
},
|
|
39
|
+
followRedirects: false,
|
|
40
|
+
changeOrigin: true,
|
|
41
|
+
onProxyReq: (proxyRequest, incomingRequest) => {
|
|
42
|
+
// Fix up any Host header. We ignore any current value and
|
|
43
|
+
// always replace it with the target host.
|
|
44
|
+
// Host: <host>:<port>
|
|
45
|
+
const hostHeader = incomingRequest.headers.host;
|
|
46
|
+
if (hostHeader !== target) {
|
|
47
|
+
proxyRequest.setHeader(HOST, targetHost);
|
|
48
|
+
}
|
|
49
|
+
// Add Forwarded header per https://git.soma.salesforce.com/pages/benjamin-fry/lwr-on-mrt-designs/request_path.html
|
|
50
|
+
proxyRequest.setHeader('Forwarded', `host=${hostHeader}`);
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function resolveLogLevel(currentLevel) {
|
|
56
|
+
// uplift VERBOSE to DEBUG; otherwise using runtime loglevel;
|
|
57
|
+
if (currentLevel === VERBOSE || currentLevel === DEBUG)
|
|
58
|
+
return ProxyLogLevels.Debug;
|
|
59
|
+
if (currentLevel === INFO)
|
|
60
|
+
return ProxyLogLevels.Info;
|
|
61
|
+
if (currentLevel === ERROR)
|
|
62
|
+
return ProxyLogLevels.Info;
|
|
63
|
+
if (currentLevel === WARN)
|
|
64
|
+
return ProxyLogLevels.Info;
|
|
65
|
+
// default log level
|
|
66
|
+
return ProxyLogLevels.Silent;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Application as ExpressApp } from 'express';
|
|
2
|
+
export interface ProxyConfiguration {
|
|
3
|
+
proxyConfigs: ProxyConfigDefinition[];
|
|
4
|
+
}
|
|
5
|
+
type ProxyConfigDefinition = Array<string>;
|
|
6
|
+
export interface LwrProxyServerConfig extends ProxyConfiguration {
|
|
7
|
+
port: number;
|
|
8
|
+
defaultHost: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A simple configuration-enabled local development proxy server.
|
|
12
|
+
*/
|
|
13
|
+
export declare class LwrProxyServer {
|
|
14
|
+
proxyServer: ExpressApp;
|
|
15
|
+
config: LwrProxyServerConfig;
|
|
16
|
+
constructor(config: LwrProxyServerConfig);
|
|
17
|
+
listen(callback?: ((opts: {
|
|
18
|
+
port: number;
|
|
19
|
+
}) => void) | undefined): Promise<{
|
|
20
|
+
port: number;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=proxy-server.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { addLocalProxyMiddleware, addRemoteProxyMiddleware } from './middleware.js';
|
|
3
|
+
/**
|
|
4
|
+
* A simple configuration-enabled local development proxy server.
|
|
5
|
+
*/
|
|
6
|
+
export class LwrProxyServer {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.proxyServer = express();
|
|
9
|
+
this.config = config;
|
|
10
|
+
addRemoteProxyMiddleware(this.proxyServer, this.config);
|
|
11
|
+
addLocalProxyMiddleware(this.proxyServer, this.config.defaultHost);
|
|
12
|
+
}
|
|
13
|
+
async listen(callback) {
|
|
14
|
+
const { proxyServer, config } = this;
|
|
15
|
+
const { port } = config;
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const server = proxyServer.listen(port, async () => {
|
|
18
|
+
const opts = { port };
|
|
19
|
+
callback?.(opts);
|
|
20
|
+
resolve(opts);
|
|
21
|
+
});
|
|
22
|
+
const handleError = (err) => {
|
|
23
|
+
server.off('error', handleError);
|
|
24
|
+
if (err.code === 'EADDRINUSE') {
|
|
25
|
+
err = new Error(`Port ${port} is already in use.`);
|
|
26
|
+
}
|
|
27
|
+
reject(err);
|
|
28
|
+
};
|
|
29
|
+
server.on('error', handleError);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=proxy-server.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lwrjs/dev-proxy-server",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"version": "0.11.0-alpha.10",
|
|
8
|
+
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr.git",
|
|
12
|
+
"directory": "packages/@lwrjs/dev-proxy-server"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr/issues"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"types": "build/es/index.d.ts",
|
|
19
|
+
"main": "build/cjs/index.cjs",
|
|
20
|
+
"module": "build/es/index.js",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": "./build/es/index.js",
|
|
24
|
+
"require": "./build/cjs/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"build/**/*.js",
|
|
29
|
+
"build/**/*.cjs",
|
|
30
|
+
"build/**/*.d.ts"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@lwrjs/diagnostics": "0.11.0-alpha.10",
|
|
34
|
+
"@lwrjs/shared-utils": "0.11.0-alpha.10",
|
|
35
|
+
"express": "^4.18.2",
|
|
36
|
+
"http-proxy-middleware": "0.21.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@lwrjs/types": "0.11.0-alpha.10"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=16.0.0 <19"
|
|
43
|
+
},
|
|
44
|
+
"gitHead": "34b1e289e8de12531f5624b64512e870157195d4"
|
|
45
|
+
}
|