@lwc/lwc-dev-server 10.2.1 → 10.3.0
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/README.md +0 -6
- package/dist/bin.js +31 -0
- package/dist/bin.js.map +1 -0
- package/dist/server/bundler/lexBundler.spec.d.ts +1 -0
- package/dist/server/bundler/lexBundler.spec.js +71 -0
- package/dist/server/bundler/lexBundler.spec.js.map +1 -0
- package/dist/server/connection/client.d.ts +2 -19
- package/dist/server/connection/client.js +3 -40
- package/dist/server/connection/client.js.map +1 -1
- package/dist/server/connection/client.spec.d.ts +1 -0
- package/dist/server/connection/client.spec.js +107 -0
- package/dist/server/connection/client.spec.js.map +1 -0
- package/dist/server/connection/connection.d.ts +1 -1
- package/dist/server/connection/connection.js +4 -12
- package/dist/server/connection/connection.js.map +1 -1
- package/dist/server/connection/connection.spec.d.ts +1 -0
- package/dist/server/connection/connection.spec.js +60 -0
- package/dist/server/connection/connection.spec.js.map +1 -0
- package/dist/server/connection/web-socket-server.d.ts +10 -8
- package/dist/server/connection/web-socket-server.js +80 -51
- package/dist/server/connection/web-socket-server.js.map +1 -1
- package/dist/server/connection/web-socket-server.spec.d.ts +1 -0
- package/dist/server/connection/web-socket-server.spec.js +174 -0
- package/dist/server/connection/web-socket-server.spec.js.map +1 -0
- package/dist/server/index.d.ts +6 -18
- package/dist/server/index.js +33 -111
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.spec.d.ts +1 -0
- package/dist/server/index.spec.js +98 -0
- package/dist/server/index.spec.js.map +1 -0
- package/dist/server/moduleGraph/index.js +19 -20
- package/dist/server/moduleGraph/index.js.map +1 -1
- package/dist/server/moduleGraph/index.spec.d.ts +1 -0
- package/dist/server/moduleGraph/index.spec.js +70 -0
- package/dist/server/moduleGraph/index.spec.js.map +1 -0
- package/dist/server/moduleGraph/workspaceScanner/__tests__/sfcli.spec.d.ts +1 -0
- package/dist/server/moduleGraph/workspaceScanner/__tests__/sfcli.spec.js +22 -0
- package/dist/server/moduleGraph/workspaceScanner/__tests__/sfcli.spec.js.map +1 -0
- package/dist/server/util/fileUtil.d.ts +0 -1
- package/dist/server/util/fileUtil.js +2 -10
- package/dist/server/util/fileUtil.js.map +1 -1
- package/dist/server/watcher/index.spec.d.ts +1 -0
- package/dist/server/watcher/index.spec.js +33 -0
- package/dist/server/watcher/index.spec.js.map +1 -0
- package/dist/types/devServer.d.ts +1 -2
- package/dist/types/devServer.js +1 -7
- package/dist/types/devServer.js.map +1 -1
- package/dist/utils/utils.test.d.ts +1 -0
- package/dist/utils/utils.test.js +49 -0
- package/dist/utils/utils.test.js.map +1 -0
- package/package.json +3 -7
- package/bin/dev-server.js +0 -2
- package/dist/cli/cli.js +0 -4
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/commands/devServer.d.ts +0 -2
- package/dist/cli/commands/devServer.js +0 -188
- package/dist/cli/commands/devServer.js.map +0 -1
- package/dist/cli/commands/index.d.ts +0 -2
- package/dist/cli/commands/index.js +0 -21
- package/dist/cli/commands/index.js.map +0 -1
- /package/dist/{cli/cli.d.ts → bin.d.ts} +0 -0
|
@@ -11,6 +11,8 @@ import { WebSocketServer } from 'ws';
|
|
|
11
11
|
import { LogLevel } from '../../types/index.js';
|
|
12
12
|
import { templateString } from '../../utils/utils.js';
|
|
13
13
|
import { WSS_STARTUP_FAILURE } from '../../labels.js';
|
|
14
|
+
import { decrypt } from '../util/aes.js';
|
|
15
|
+
import { Connection } from './connection.js';
|
|
14
16
|
/**
|
|
15
17
|
* Special mechanism to take internal users through an authentication flow.
|
|
16
18
|
*/
|
|
@@ -32,10 +34,10 @@ function requestHandler(req, res) {
|
|
|
32
34
|
res.end(`Visit https://<salesforce-url>?0.aura.mode=devpreview`);
|
|
33
35
|
}
|
|
34
36
|
const TRUSTED_ORIGINS = [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
/\.sfdcdev\.force\.com:[0-9]+$/,
|
|
38
|
+
/\.w[a-z]\.crm\.dev:6101$/,
|
|
39
|
+
/\.lightning\.force\.com$/,
|
|
40
|
+
/\.lightning\.pc-rnd\.force\.com$/,
|
|
39
41
|
];
|
|
40
42
|
function isFromTrustedOrigin(request) {
|
|
41
43
|
const { headers } = request;
|
|
@@ -45,60 +47,87 @@ function isFromTrustedOrigin(request) {
|
|
|
45
47
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications#protocols
|
|
46
48
|
headers['sec-websocket-protocol'] === 'lightning-dev-preview' &&
|
|
47
49
|
origin &&
|
|
48
|
-
TRUSTED_ORIGINS.some((trustedOrigin) =>
|
|
50
|
+
TRUSTED_ORIGINS.some((trustedOrigin) => trustedOrigin.test(origin)));
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* Note: Based on examples in the ws git repo: https://github.com/websockets/ws/blob/master/examples/express-session-parse/index.js
|
|
54
|
-
* @param param0
|
|
55
|
-
* @param logger
|
|
56
|
-
* @returns
|
|
53
|
+
* Wrapper over WebSocketServer that does authentication and produces `Connection`s
|
|
57
54
|
*/
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
httpsServer.on('request', requestHandler);
|
|
84
|
-
httpsServer.on('upgrade', upgradeHandler);
|
|
85
|
-
httpsServer.listen(httpsConfig.port, () => {
|
|
86
|
-
logger.log(LogLevel.info, `[LWC Dev Server] LWC HTTPS Dev Server started at port:${httpsConfig.port}`);
|
|
55
|
+
export class AuthenticatedWebSocketServer {
|
|
56
|
+
constructor({ port, https: httpsConfig, identityToken }, logger) {
|
|
57
|
+
this.logger = logger;
|
|
58
|
+
try {
|
|
59
|
+
// Start a WebSocketServer disconnected from the http server, allows us to handle authantication before upgrading ws connections
|
|
60
|
+
this.wss = new WebSocketServer({ noServer: true });
|
|
61
|
+
this.identityToken = identityToken;
|
|
62
|
+
const httpServer = http.createServer();
|
|
63
|
+
httpServer.maxRequestsPerSocket = 1;
|
|
64
|
+
// Special handler for the internal usecase
|
|
65
|
+
httpServer.on('request', requestHandler);
|
|
66
|
+
const upgradeHandler = (request, socket, head) => {
|
|
67
|
+
if (!isFromTrustedOrigin(request)) {
|
|
68
|
+
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
|
69
|
+
socket.destroy();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.wss.handleUpgrade(request, socket, head, (ws) => {
|
|
73
|
+
this.wss.emit('connection', ws, request);
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
// Handle upgrade of connections after verifying the validity
|
|
77
|
+
httpServer.on('upgrade', upgradeHandler);
|
|
78
|
+
httpServer.listen(port, () => {
|
|
79
|
+
logger.log(LogLevel.info, `[LWC Dev Server] LWC Dev Server started at port:${port}`);
|
|
87
80
|
});
|
|
88
|
-
|
|
89
|
-
httpsServer.
|
|
81
|
+
if (httpsConfig) {
|
|
82
|
+
const httpsServer = https.createServer(httpsConfig);
|
|
83
|
+
httpsServer.on('request', requestHandler);
|
|
84
|
+
httpsServer.on('upgrade', upgradeHandler);
|
|
85
|
+
httpsServer.listen(httpsConfig.port, () => {
|
|
86
|
+
logger.log(LogLevel.info, `[LWC Dev Server] LWC HTTPS Dev Server started at port:${httpsConfig.port}`);
|
|
87
|
+
});
|
|
88
|
+
this.wss.on('close', () => {
|
|
89
|
+
httpsServer.close();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// When the WebSocketServer is being closed, close the http server as well.
|
|
93
|
+
this.wss.on('close', () => {
|
|
94
|
+
httpServer.close();
|
|
90
95
|
});
|
|
91
96
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
catch (e) {
|
|
98
|
+
const errorMsg = templateString(WSS_STARTUP_FAILURE, [e]);
|
|
99
|
+
logger.log(LogLevel.error, errorMsg);
|
|
100
|
+
throw e;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
close() {
|
|
104
|
+
this.wss.close();
|
|
97
105
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
onNewConnection(callback) {
|
|
107
|
+
this.wss.on('connection', (ws, request) => {
|
|
108
|
+
const connection = new Connection(ws, this.logger);
|
|
109
|
+
const searchParams = new URL(request.url, 'http://localhost').searchParams;
|
|
110
|
+
if (this.identityToken) {
|
|
111
|
+
const sessionTokenCipher = searchParams.get('sessionTokenCipher');
|
|
112
|
+
if (!sessionTokenCipher) {
|
|
113
|
+
this.logger.log(LogLevel.error, 'sessionTokenCipher not present. Terminating.');
|
|
114
|
+
ws.close();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const sessionToken = decrypt(sessionTokenCipher, this.identityToken);
|
|
118
|
+
connection.send({
|
|
119
|
+
type: 'auth-response',
|
|
120
|
+
data: { sessionToken: sessionToken },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const referer = searchParams.get('referer');
|
|
124
|
+
if (!referer) {
|
|
125
|
+
this.logger.log(LogLevel.error, 'Referer param not present. Terminating.');
|
|
126
|
+
ws.close();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
callback(connection, referer);
|
|
130
|
+
});
|
|
102
131
|
}
|
|
103
132
|
}
|
|
104
133
|
//# sourceMappingURL=web-socket-server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-socket-server.js","sourceRoot":"","sources":["../../../src/server/connection/web-socket-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAwB,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"web-socket-server.js","sourceRoot":"","sources":["../../../src/server/connection/web-socket-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
3
|
+
import { WebSocketServer } from 'ws';
|
|
4
|
+
import { LogLevel, Workspace } from '../../types';
|
|
5
|
+
import * as aes from '../util/aes';
|
|
6
|
+
import { AuthenticatedWebSocketServer } from './web-socket-server.js';
|
|
7
|
+
import { Connection } from './connection';
|
|
8
|
+
// Mock dependencies
|
|
9
|
+
vi.mock('ws');
|
|
10
|
+
vi.mock('http');
|
|
11
|
+
vi.mock('https');
|
|
12
|
+
vi.mock('../util/aes');
|
|
13
|
+
vi.mock('./connection');
|
|
14
|
+
describe('AuthenticatedWebSocketServer', () => {
|
|
15
|
+
let logger;
|
|
16
|
+
let serverConfig;
|
|
17
|
+
let wsServerMock;
|
|
18
|
+
let httpServerMock;
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
logger = {
|
|
21
|
+
log: vi.fn(),
|
|
22
|
+
};
|
|
23
|
+
serverConfig = {
|
|
24
|
+
port: 3000,
|
|
25
|
+
identityToken: 'mock-identity-token',
|
|
26
|
+
rootDir: '',
|
|
27
|
+
logLevel: LogLevel.debug,
|
|
28
|
+
paths: [],
|
|
29
|
+
workspace: Workspace.Internal,
|
|
30
|
+
};
|
|
31
|
+
wsServerMock = {
|
|
32
|
+
on: vi.fn(),
|
|
33
|
+
handleUpgrade: vi.fn(),
|
|
34
|
+
emit: vi.fn(),
|
|
35
|
+
close: vi.fn(),
|
|
36
|
+
};
|
|
37
|
+
httpServerMock = {
|
|
38
|
+
on: vi.fn(),
|
|
39
|
+
listen: vi.fn(),
|
|
40
|
+
close: vi.fn(),
|
|
41
|
+
};
|
|
42
|
+
vi.mocked(WebSocketServer).mockImplementation(() => wsServerMock);
|
|
43
|
+
vi.mocked(http.createServer).mockReturnValue(httpServerMock);
|
|
44
|
+
});
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
it('should create an instance of AuthenticatedWebSocketServer and start the HTTP server', () => {
|
|
49
|
+
new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
50
|
+
expect(http.createServer).toHaveBeenCalled();
|
|
51
|
+
expect(httpServerMock.on).toHaveBeenCalledWith('request', expect.any(Function));
|
|
52
|
+
expect(httpServerMock.on).toHaveBeenCalledWith('upgrade', expect.any(Function));
|
|
53
|
+
expect(httpServerMock.listen).toHaveBeenCalledWith(serverConfig.port, expect.any(Function));
|
|
54
|
+
});
|
|
55
|
+
it('should handle WebSocket upgrade requests from trusted origins', () => {
|
|
56
|
+
const socketMock = {
|
|
57
|
+
write: vi.fn(),
|
|
58
|
+
destroy: vi.fn(),
|
|
59
|
+
};
|
|
60
|
+
new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
61
|
+
const upgradeHandler = vi
|
|
62
|
+
.mocked(httpServerMock)
|
|
63
|
+
.on.mock.calls.find((call) => call[0] === 'upgrade')[1];
|
|
64
|
+
const requestMock = {
|
|
65
|
+
headers: {
|
|
66
|
+
'sec-websocket-protocol': 'lightning-dev-preview',
|
|
67
|
+
origin: 'https://mock-origin.lightning.force.com',
|
|
68
|
+
},
|
|
69
|
+
url: '/',
|
|
70
|
+
};
|
|
71
|
+
const headMock = Buffer.alloc(0);
|
|
72
|
+
// @ts-expect-error can't mock the entire socket
|
|
73
|
+
upgradeHandler(requestMock, socketMock, headMock);
|
|
74
|
+
expect(wsServerMock.handleUpgrade).toHaveBeenCalledWith(requestMock, socketMock, headMock, expect.any(Function));
|
|
75
|
+
});
|
|
76
|
+
it('should reject WebSocket upgrade requests from untrusted origins', () => {
|
|
77
|
+
const httpServerMock = {
|
|
78
|
+
on: vi.fn(),
|
|
79
|
+
listen: vi.fn(),
|
|
80
|
+
close: vi.fn(),
|
|
81
|
+
};
|
|
82
|
+
vi.mocked(http.createServer).mockReturnValue(httpServerMock);
|
|
83
|
+
const socketMock = {
|
|
84
|
+
write: vi.fn(),
|
|
85
|
+
destroy: vi.fn(),
|
|
86
|
+
};
|
|
87
|
+
new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
88
|
+
const upgradeHandler = vi
|
|
89
|
+
.mocked(httpServerMock)
|
|
90
|
+
.on.mock.calls.find((call) => call[0] === 'upgrade')[1];
|
|
91
|
+
const requestMock = {
|
|
92
|
+
headers: {
|
|
93
|
+
'sec-websocket-protocol': 'unknown-protocol',
|
|
94
|
+
origin: 'https://untrusted-origin.com',
|
|
95
|
+
},
|
|
96
|
+
url: '/',
|
|
97
|
+
};
|
|
98
|
+
const headMock = Buffer.alloc(0);
|
|
99
|
+
// @ts-expect-error can't mock the entire socket
|
|
100
|
+
upgradeHandler(requestMock, socketMock, headMock);
|
|
101
|
+
expect(socketMock.write).toHaveBeenCalledWith('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
|
102
|
+
expect(socketMock.destroy).toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
it('should close the WebSocketServer when close() is called', () => {
|
|
105
|
+
const authenticatedWSS = new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
106
|
+
authenticatedWSS.close();
|
|
107
|
+
expect(wsServerMock.close).toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
it('should handle a new WebSocket connection and send an auth-response if identityToken is provided', () => {
|
|
110
|
+
const connectionMock = {
|
|
111
|
+
send: vi.fn(),
|
|
112
|
+
};
|
|
113
|
+
vi.mocked(Connection).mockReturnValue(connectionMock);
|
|
114
|
+
const wsMock = {};
|
|
115
|
+
const requestMock = {
|
|
116
|
+
url: '/?sessionTokenCipher=mock-cipher&referer=https://mock-referer.com',
|
|
117
|
+
};
|
|
118
|
+
const decryptSpy = vi.spyOn(aes, 'decrypt').mockReturnValue('decrypted-token');
|
|
119
|
+
const authenticatedWSS = new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
120
|
+
const callback = vi.fn();
|
|
121
|
+
authenticatedWSS.onNewConnection(callback);
|
|
122
|
+
vi.mocked(wsServerMock)
|
|
123
|
+
.on.mock.calls.find((call) => call[0] === 'connection')[1]
|
|
124
|
+
.call(wsServerMock, wsMock, requestMock);
|
|
125
|
+
expect(Connection).toHaveBeenCalledWith(wsMock, logger);
|
|
126
|
+
expect(decryptSpy).toHaveBeenCalledWith('mock-cipher', serverConfig.identityToken);
|
|
127
|
+
expect(connectionMock.send).toHaveBeenCalledWith({
|
|
128
|
+
type: 'auth-response',
|
|
129
|
+
data: { sessionToken: 'decrypted-token' },
|
|
130
|
+
});
|
|
131
|
+
expect(callback).toHaveBeenCalledWith(connectionMock, 'https://mock-referer.com');
|
|
132
|
+
});
|
|
133
|
+
it('should close WebSocket connection if sessionTokenCipher is missing', () => {
|
|
134
|
+
const connectionMock = {
|
|
135
|
+
send: vi.fn(),
|
|
136
|
+
};
|
|
137
|
+
vi.mocked(Connection).mockReturnValue(connectionMock);
|
|
138
|
+
const wsMock = {
|
|
139
|
+
close: vi.fn(),
|
|
140
|
+
};
|
|
141
|
+
const requestMock = {
|
|
142
|
+
url: '/',
|
|
143
|
+
headers: {
|
|
144
|
+
referer: 'https://mock-referer.com',
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
const authenticatedWSS = new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
148
|
+
const callback = vi.fn();
|
|
149
|
+
authenticatedWSS.onNewConnection(callback);
|
|
150
|
+
vi.mocked(wsServerMock)
|
|
151
|
+
.on.mock.calls.find((call) => call[0] === 'connection')[1]
|
|
152
|
+
.call(wsServerMock, wsMock, requestMock);
|
|
153
|
+
expect(wsMock.close).toHaveBeenCalled();
|
|
154
|
+
expect(callback).not.toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
it('should close WebSocket connection if referer header is missing', () => {
|
|
157
|
+
const wsMock = {
|
|
158
|
+
close: vi.fn(),
|
|
159
|
+
};
|
|
160
|
+
const requestMock = {
|
|
161
|
+
url: '/?sessionTokenCipher=mock-cipher',
|
|
162
|
+
headers: {},
|
|
163
|
+
};
|
|
164
|
+
const authenticatedWSS = new AuthenticatedWebSocketServer(serverConfig, logger);
|
|
165
|
+
const callback = vi.fn();
|
|
166
|
+
authenticatedWSS.onNewConnection(callback);
|
|
167
|
+
vi.mocked(wsServerMock)
|
|
168
|
+
.on.mock.calls.find((call) => call[0] === 'connection')[1]
|
|
169
|
+
.call(wsServerMock, wsMock, requestMock);
|
|
170
|
+
expect(wsMock.close).toHaveBeenCalled();
|
|
171
|
+
expect(callback).not.toHaveBeenCalled();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
//# sourceMappingURL=web-socket-server.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-socket-server.spec.js","sourceRoot":"","sources":["../../../src/server/connection/web-socket-server.spec.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { FSWatcher } from 'chokidar';
|
|
2
|
-
import * as Websocket from 'ws';
|
|
3
2
|
import { DevServerContext, type Logger, type ServerConfig } from '../types/index.js';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
3
|
+
import { AuthenticatedWebSocketServer } from './connection/web-socket-server.js';
|
|
4
|
+
import { Client } from './connection/client.js';
|
|
6
5
|
/**
|
|
7
6
|
* This class represents the central place where the LWC dev server coordination occurs.
|
|
8
7
|
*
|
|
@@ -14,24 +13,13 @@ import type { WebSocketServer } from 'ws';
|
|
|
14
13
|
*/
|
|
15
14
|
export declare class LWCServer {
|
|
16
15
|
watcher: FSWatcher;
|
|
17
|
-
|
|
18
|
-
wss:
|
|
16
|
+
clients: Set<Client>;
|
|
17
|
+
wss: AuthenticatedWebSocketServer;
|
|
19
18
|
context: DevServerContext;
|
|
20
19
|
identityToken?: string;
|
|
21
|
-
constructor(config: ServerConfig, wss:
|
|
22
|
-
/**
|
|
23
|
-
* Initialize the WebSocketServer by adding message handlers for connections lifecycle events.
|
|
24
|
-
*/
|
|
25
|
-
init(): void;
|
|
20
|
+
constructor(config: ServerConfig, wss: AuthenticatedWebSocketServer, logger: Logger);
|
|
26
21
|
stopServer(): void;
|
|
27
|
-
moduleUpdateHandler(modulePath: string)
|
|
28
|
-
/**
|
|
29
|
-
* A one time message handler for new clients.
|
|
30
|
-
* This method is responsible for authenticating the client connection and once authenticated,
|
|
31
|
-
* the communication is handed over to the Client object.
|
|
32
|
-
*/
|
|
33
|
-
newClientMessageCallback({ data: rawData, target: socket }: Websocket.MessageEvent): void;
|
|
34
|
-
clientCloseHandler({ target: socket }: Websocket.ErrorEvent | Websocket.CloseEvent): void;
|
|
22
|
+
moduleUpdateHandler: (modulePath: string) => void;
|
|
35
23
|
}
|
|
36
24
|
/**
|
|
37
25
|
* Initialize an LWC Dev Server with the specified server configuration.
|
package/dist/server/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { LogLevel
|
|
2
|
-
import { IGNORING_PREINIT_RESPONSES, UNRECOGNIZED_MESSAGE_TYPE } from '../labels.js';
|
|
1
|
+
import { LogLevel } from '../types/index.js';
|
|
3
2
|
import { startWatch } from './watcher/index.js';
|
|
4
|
-
import {
|
|
3
|
+
import { AuthenticatedWebSocketServer } from './connection/web-socket-server.js';
|
|
5
4
|
import { ModuleGraph } from './moduleGraph/index.js';
|
|
6
5
|
import ConsoleLogger from './consoleLogger.js';
|
|
7
|
-
import { Client
|
|
8
|
-
import { Connection } from './connection/connection.js';
|
|
9
|
-
import { decrypt } from './util/aes.js';
|
|
6
|
+
import { Client } from './connection/client.js';
|
|
10
7
|
/**
|
|
11
8
|
* This class represents the central place where the LWC dev server coordination occurs.
|
|
12
9
|
*
|
|
@@ -18,127 +15,52 @@ import { decrypt } from './util/aes.js';
|
|
|
18
15
|
*/
|
|
19
16
|
export class LWCServer {
|
|
20
17
|
constructor(config, wss, logger) {
|
|
21
|
-
this.
|
|
18
|
+
this.clients = new Set();
|
|
19
|
+
this.moduleUpdateHandler = (modulePath) => {
|
|
20
|
+
for (const client of this.clients) {
|
|
21
|
+
client.send({ type: 'update', data: [{ modulePath }] });
|
|
22
|
+
}
|
|
23
|
+
};
|
|
22
24
|
// Dev Server to manage critical assets, allows them to be closed and avoid memory leaks
|
|
23
25
|
this.wss = wss;
|
|
24
26
|
this.watcher = startWatch(config.paths);
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
once: true,
|
|
27
|
+
this.wss.onNewConnection((connection, url) => {
|
|
28
|
+
if (config.maxClientCount && this.clients.size >= config.maxClientCount) {
|
|
29
|
+
logger.log(LogLevel.error, `[LWC Dev Server] Max connection limit(${this.context.config.maxClientCount}) reached, ignoring new requests until existing connections are closed`);
|
|
30
|
+
connection.close();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const clientId = crypto.randomUUID();
|
|
34
|
+
const client = new Client(clientId, url, connection, this.context);
|
|
35
|
+
this.clients.add(client);
|
|
36
|
+
client.onClose(() => this.clients.delete(client));
|
|
37
|
+
this.context.config.lifecycle?.emitTelemetry({
|
|
38
|
+
eventName: 'connection-success',
|
|
39
|
+
clientId: clientId,
|
|
40
|
+
clientType: this.context.config.clientType ?? 'unknown',
|
|
41
|
+
clientCount: this.clients.size,
|
|
41
42
|
});
|
|
42
|
-
ws.addEventListener('close', this.clientCloseHandler.bind(this), { once: true });
|
|
43
|
-
ws.addEventListener('error', this.clientCloseHandler.bind(this), { once: true });
|
|
44
43
|
});
|
|
45
44
|
this.watcher.on('error', (event) => {
|
|
46
45
|
this.context.logger.log(LogLevel.error, '[LWC Dev Server] Encountered error while watching files');
|
|
47
46
|
this.context.logger.log(LogLevel.debug, `[LWC Dev Server] File watcher error: ${event.message}`);
|
|
48
47
|
this.stopServer();
|
|
49
48
|
});
|
|
49
|
+
this.context = {
|
|
50
|
+
config,
|
|
51
|
+
logger,
|
|
52
|
+
moduleGraph: new ModuleGraph(config, logger, this.watcher, {
|
|
53
|
+
moduleUpdateHandler: this.moduleUpdateHandler,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
this.identityToken = config.identityToken;
|
|
50
57
|
}
|
|
51
58
|
stopServer() {
|
|
52
59
|
this.context.logger.log(LogLevel.info, '[LWC Dev Server] Stopping the dev server');
|
|
53
60
|
this.watcher.close();
|
|
54
|
-
this.clientPool.reset();
|
|
55
61
|
this.wss.close();
|
|
56
62
|
this.context.logger.log(LogLevel.info, '[LWC Dev Server] Succesfully stopped dev server');
|
|
57
63
|
}
|
|
58
|
-
moduleUpdateHandler(modulePath) {
|
|
59
|
-
const hotModule = { type: 'update', data: [{ modulePath }] };
|
|
60
|
-
this.clientPool.sendModuleUpdateBroadcast(hotModule);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* A one time message handler for new clients.
|
|
64
|
-
* This method is responsible for authenticating the client connection and once authenticated,
|
|
65
|
-
* the communication is handed over to the Client object.
|
|
66
|
-
*/
|
|
67
|
-
newClientMessageCallback({ data: rawData, target: socket }) {
|
|
68
|
-
const { context: { logger, config: { lifecycle }, }, } = this;
|
|
69
|
-
let payload;
|
|
70
|
-
if (typeof rawData === 'string') {
|
|
71
|
-
try {
|
|
72
|
-
payload = JSON.parse(rawData);
|
|
73
|
-
}
|
|
74
|
-
catch (e) {
|
|
75
|
-
logger.log(LogLevel.error, 'Failed to read message sent by hmr-client. Client connected from ' +
|
|
76
|
-
socket.url);
|
|
77
|
-
socket.close();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const data = payload;
|
|
81
|
-
if (data.type == undefined) {
|
|
82
|
-
logger.log(LogLevel.error, UNRECOGNIZED_MESSAGE_TYPE);
|
|
83
|
-
socket.close();
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
switch (data.type) {
|
|
87
|
-
case 'init': {
|
|
88
|
-
const { data: { clientId, url, auth }, } = data;
|
|
89
|
-
if (this.clientPool.size() === this.context.config.maxClientCount) {
|
|
90
|
-
logger.log(LogLevel.error, `[LWC Dev Server] Max connection limit(${this.context.config.maxClientCount}) reached, ignoring new requests until existing connections are closed`);
|
|
91
|
-
socket.close();
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const connection = new Connection(socket, logger);
|
|
95
|
-
const client = new Client(clientId, url, connection, this.context);
|
|
96
|
-
this.clientPool.addClient(socket, client);
|
|
97
|
-
logger.log(LogLevel.info, `[LWC Dev Server] New connection for url: ${url} registered. Client ID: ${clientId}`);
|
|
98
|
-
// TODO: The server should decode the auth challenge with its session key and return the challenge phrase
|
|
99
|
-
if (this.identityToken) {
|
|
100
|
-
if (!auth) {
|
|
101
|
-
logger.log(LogLevel.error, `[LWC Dev Server] Auth required`);
|
|
102
|
-
socket.close();
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
const decrypted = decrypt(auth.data.sessionTokenCipher, this.identityToken);
|
|
107
|
-
client.send({ type: 'auth-response', data: { sessionToken: decrypted } });
|
|
108
|
-
lifecycle?.emitTelemetry({
|
|
109
|
-
eventName: 'connection-success',
|
|
110
|
-
clientId: clientId,
|
|
111
|
-
clientType: this.context.config.clientType ?? 'unknown',
|
|
112
|
-
clientCount: this.clientPool.size(),
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
catch (e) {
|
|
116
|
-
logger.log(LogLevel.error, `[LWC Dev Server] Failed to decrypt sessionToken. Closing socket.`);
|
|
117
|
-
socket.close();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
default: {
|
|
123
|
-
logger.log(LogLevel.warn, IGNORING_PREINIT_RESPONSES);
|
|
124
|
-
socket.close();
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
clientCloseHandler({ target: socket }) {
|
|
130
|
-
const client = this.clientPool.socketToClientMap.get(socket);
|
|
131
|
-
if (!client) {
|
|
132
|
-
// Should never get here, but if we do then forcefully shut the socket
|
|
133
|
-
this.context.logger.log(LogLevel.error, '[LWC Dev Server] Unrecognized client, shutting down the socket');
|
|
134
|
-
socket.close();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
// Else let the client handle the cleanup
|
|
138
|
-
client.close();
|
|
139
|
-
this.clientPool.removeClient(client);
|
|
140
|
-
this.context.logger.log(LogLevel.info, `[LWC Dev Server] Closing client. Client ID: ${client.clientId}`);
|
|
141
|
-
}
|
|
142
64
|
}
|
|
143
65
|
/**
|
|
144
66
|
* Initialize an LWC Dev Server with the specified server configuration.
|
|
@@ -146,7 +68,7 @@ export class LWCServer {
|
|
|
146
68
|
*/
|
|
147
69
|
export async function startLwcDevServer(config) {
|
|
148
70
|
const logger = new ConsoleLogger(config.logLevel);
|
|
149
|
-
const wss =
|
|
71
|
+
const wss = new AuthenticatedWebSocketServer(config, logger);
|
|
150
72
|
return new LWCServer(config, wss, logger);
|
|
151
73
|
}
|
|
152
74
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|