@hubspot/ui-extensions-dev-server 1.0.2 → 1.1.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.
Files changed (95) hide show
  1. package/package.json +1 -1
  2. package/dist/index.d.ts +0 -4
  3. package/dist/index.js +0 -4
  4. package/dist/lib/DevModeInterface.d.ts +0 -9
  5. package/dist/lib/DevModeInterface.js +0 -36
  6. package/dist/lib/DevModeParentInterface.d.ts +0 -19
  7. package/dist/lib/DevModeParentInterface.js +0 -181
  8. package/dist/lib/DevModeUnifiedInterface.d.ts +0 -9
  9. package/dist/lib/DevModeUnifiedInterface.js +0 -118
  10. package/dist/lib/DevServerState.d.ts +0 -44
  11. package/dist/lib/DevServerState.js +0 -95
  12. package/dist/lib/ExtensionsWebSocket.d.ts +0 -25
  13. package/dist/lib/ExtensionsWebSocket.js +0 -110
  14. package/dist/lib/__mocks__/config.d.ts +0 -2
  15. package/dist/lib/__mocks__/config.js +0 -5
  16. package/dist/lib/__mocks__/isExtensionFile.d.ts +0 -5
  17. package/dist/lib/__mocks__/isExtensionFile.js +0 -11
  18. package/dist/lib/__tests__/DevModeInterface.spec.d.ts +0 -1
  19. package/dist/lib/__tests__/DevModeInterface.spec.js +0 -155
  20. package/dist/lib/__tests__/DevModeParentInterface.spec.d.ts +0 -1
  21. package/dist/lib/__tests__/DevModeParentInterface.spec.js +0 -179
  22. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.d.ts +0 -1
  23. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.js +0 -236
  24. package/dist/lib/__tests__/ExtensionsWebSocket.spec.d.ts +0 -1
  25. package/dist/lib/__tests__/ExtensionsWebSocket.spec.js +0 -304
  26. package/dist/lib/__tests__/ast.spec.d.ts +0 -1
  27. package/dist/lib/__tests__/ast.spec.js +0 -737
  28. package/dist/lib/__tests__/build.spec.d.ts +0 -1
  29. package/dist/lib/__tests__/build.spec.js +0 -159
  30. package/dist/lib/__tests__/config.spec.d.ts +0 -1
  31. package/dist/lib/__tests__/config.spec.js +0 -291
  32. package/dist/lib/__tests__/dev.spec.d.ts +0 -1
  33. package/dist/lib/__tests__/dev.spec.js +0 -80
  34. package/dist/lib/__tests__/extensionsService.spec.d.ts +0 -1
  35. package/dist/lib/__tests__/extensionsService.spec.js +0 -150
  36. package/dist/lib/__tests__/factories.d.ts +0 -48
  37. package/dist/lib/__tests__/factories.js +0 -32
  38. package/dist/lib/__tests__/fixtures/extensionConfig.d.ts +0 -182
  39. package/dist/lib/__tests__/fixtures/extensionConfig.js +0 -304
  40. package/dist/lib/__tests__/fixtures/urls.d.ts +0 -4
  41. package/dist/lib/__tests__/fixtures/urls.js +0 -4
  42. package/dist/lib/__tests__/parsing-utils.spec.d.ts +0 -1
  43. package/dist/lib/__tests__/parsing-utils.spec.js +0 -467
  44. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.d.ts +0 -1
  45. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.js +0 -112
  46. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.d.ts +0 -1
  47. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.js +0 -111
  48. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.d.ts +0 -1
  49. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.js +0 -256
  50. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.d.ts +0 -1
  51. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.js +0 -65
  52. package/dist/lib/__tests__/plugins/manifestPlugin.spec.d.ts +0 -1
  53. package/dist/lib/__tests__/plugins/manifestPlugin.spec.js +0 -455
  54. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.d.ts +0 -1
  55. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.js +0 -81
  56. package/dist/lib/__tests__/server.spec.d.ts +0 -1
  57. package/dist/lib/__tests__/server.spec.js +0 -152
  58. package/dist/lib/__tests__/test-utils/ast.d.ts +0 -1
  59. package/dist/lib/__tests__/test-utils/ast.js +0 -4
  60. package/dist/lib/__tests__/utils.spec.d.ts +0 -1
  61. package/dist/lib/__tests__/utils.spec.js +0 -176
  62. package/dist/lib/ast.d.ts +0 -16
  63. package/dist/lib/ast.js +0 -281
  64. package/dist/lib/bin/cli.d.ts +0 -2
  65. package/dist/lib/bin/cli.js +0 -143
  66. package/dist/lib/build.d.ts +0 -24
  67. package/dist/lib/build.js +0 -73
  68. package/dist/lib/config.d.ts +0 -7
  69. package/dist/lib/config.js +0 -124
  70. package/dist/lib/constants.d.ts +0 -32
  71. package/dist/lib/constants.js +0 -43
  72. package/dist/lib/dev.d.ts +0 -2
  73. package/dist/lib/dev.js +0 -58
  74. package/dist/lib/extensionsService.d.ts +0 -10
  75. package/dist/lib/extensionsService.js +0 -45
  76. package/dist/lib/parsing-utils.d.ts +0 -31
  77. package/dist/lib/parsing-utils.js +0 -289
  78. package/dist/lib/plugins/codeBlockingPlugin.d.ts +0 -8
  79. package/dist/lib/plugins/codeBlockingPlugin.js +0 -45
  80. package/dist/lib/plugins/codeCheckingPlugin.d.ts +0 -8
  81. package/dist/lib/plugins/codeCheckingPlugin.js +0 -89
  82. package/dist/lib/plugins/devBuildPlugin.d.ts +0 -8
  83. package/dist/lib/plugins/devBuildPlugin.js +0 -201
  84. package/dist/lib/plugins/friendlyLoggingPlugin.d.ts +0 -14
  85. package/dist/lib/plugins/friendlyLoggingPlugin.js +0 -36
  86. package/dist/lib/plugins/manifestPlugin.d.ts +0 -12
  87. package/dist/lib/plugins/manifestPlugin.js +0 -158
  88. package/dist/lib/plugins/relevantModulesPlugin.d.ts +0 -13
  89. package/dist/lib/plugins/relevantModulesPlugin.js +0 -25
  90. package/dist/lib/server.d.ts +0 -13
  91. package/dist/lib/server.js +0 -99
  92. package/dist/lib/types.d.ts +0 -290
  93. package/dist/lib/types.js +0 -12
  94. package/dist/lib/utils.d.ts +0 -25
  95. package/dist/lib/utils.js +0 -113
@@ -1,304 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { ExtensionsWebSocket, isAllowedOrigin, } from "../ExtensionsWebSocket.js";
3
- import { DevServerState } from "../DevServerState.js";
4
- import { createMockLogger, createDevServerConfig } from "./factories.js";
5
- const MOCK_INTERVAL_ID = 123;
6
- let mockClients;
7
- let mockWss;
8
- let upgradeHandler = null;
9
- vi.mock('ws', () => ({
10
- WebSocketServer: vi.fn(() => {
11
- mockClients = new Set();
12
- const listeners = {};
13
- let isClosed = false;
14
- mockWss = {
15
- clients: mockClients,
16
- on: vi.fn((event, handler) => {
17
- if (!listeners[event])
18
- listeners[event] = [];
19
- listeners[event].push(handler);
20
- }),
21
- emit: vi.fn((event, ...args) => {
22
- listeners[event]?.forEach((handler) => handler(...args));
23
- }),
24
- handleUpgrade: vi.fn((request, socket, head, callback) => {
25
- const mockClient = createMockWebSocket();
26
- mockClients.add(mockClient);
27
- callback(mockClient);
28
- }),
29
- close: vi.fn((callback) => {
30
- if (isClosed) {
31
- callback?.(new Error('The server is not running'));
32
- }
33
- else {
34
- isClosed = true;
35
- callback?.();
36
- }
37
- }),
38
- };
39
- return mockWss;
40
- }),
41
- WebSocket: { OPEN: 1, CLOSED: 3 },
42
- }));
43
- function createMockWebSocket() {
44
- const listeners = {};
45
- const mockWs = {
46
- readyState: 1,
47
- on: vi.fn((event, handler) => {
48
- if (!listeners[event])
49
- listeners[event] = [];
50
- listeners[event].push(handler);
51
- }),
52
- once: vi.fn(),
53
- emit: vi.fn((event, ...args) => {
54
- listeners[event]?.forEach((handler) => handler(...args));
55
- }),
56
- send: vi.fn(),
57
- close: vi.fn(() => {
58
- mockWs.readyState = 3;
59
- mockClients.delete(mockWs);
60
- listeners['close']?.forEach((handler) => handler());
61
- }),
62
- terminate: vi.fn(() => {
63
- mockWs.readyState = 3;
64
- mockClients.delete(mockWs);
65
- }),
66
- ping: vi.fn(),
67
- };
68
- return mockWs;
69
- }
70
- let mockHttpServer;
71
- let devServerState;
72
- let extensionsWebSocket;
73
- function createMockHttpServer() {
74
- const listeners = {};
75
- return {
76
- on: vi.fn((event, handler) => {
77
- if (!listeners[event])
78
- listeners[event] = [];
79
- listeners[event].push(handler);
80
- if (event === 'upgrade') {
81
- upgradeHandler = handler;
82
- }
83
- }),
84
- emit: vi.fn((event, ...args) => {
85
- listeners[event]?.forEach((handler) => handler(...args));
86
- }),
87
- listen: vi.fn(),
88
- close: vi.fn(),
89
- };
90
- }
91
- function simulateClientConnection(origin = 'http://localhost') {
92
- if (!upgradeHandler)
93
- throw new Error('upgradeHandler not initialized');
94
- const mockRequest = { headers: { origin } };
95
- const mockSocket = { destroy: vi.fn() };
96
- upgradeHandler(mockRequest, mockSocket, Buffer.from([]));
97
- return {
98
- mockRequest,
99
- mockSocket,
100
- client: Array.from(mockClients)[mockClients.size - 1],
101
- };
102
- }
103
- describe('ExtensionsWebSocket', () => {
104
- describe('isAllowedOrigin', () => {
105
- it('should return false for undefined origin', () => {
106
- expect(isAllowedOrigin(undefined)).toBe(false);
107
- });
108
- it('should return true for localhost origins', () => {
109
- expect(isAllowedOrigin('http://localhost')).toBe(true);
110
- expect(isAllowedOrigin('https://localhost')).toBe(true);
111
- expect(isAllowedOrigin('https://localhost:8080')).toBe(true);
112
- expect(isAllowedOrigin('https://localhost:5173')).toBe(true);
113
- });
114
- it('should return true for hubspot.com origins', () => {
115
- expect(isAllowedOrigin('https://app.hubspot.com')).toBe(true);
116
- expect(isAllowedOrigin('http://hubspot.com')).toBe(true);
117
- expect(isAllowedOrigin('https://api.hubspot.com:443')).toBe(true);
118
- });
119
- it('should return true for hubspotqa.com origins', () => {
120
- expect(isAllowedOrigin('https://app.hubspotqa.com')).toBe(true);
121
- expect(isAllowedOrigin('http://hubspotqa.com')).toBe(true);
122
- expect(isAllowedOrigin('https://api.hubspotqa.com:443')).toBe(true);
123
- });
124
- it('should return false for non-allowed origins', () => {
125
- expect(isAllowedOrigin('https://evil.com')).toBe(false);
126
- expect(isAllowedOrigin('http://example.com')).toBe(false);
127
- expect(isAllowedOrigin('https://hubspot.com.evil.com')).toBe(false);
128
- });
129
- });
130
- describe('ExtensionsWebSocket class', () => {
131
- beforeEach(() => {
132
- const logger = createMockLogger();
133
- const config = createDevServerConfig(logger);
134
- devServerState = new DevServerState(config);
135
- mockHttpServer = createMockHttpServer();
136
- mockClients = new Set();
137
- });
138
- afterEach(() => {
139
- vi.useRealTimers();
140
- vi.clearAllMocks();
141
- mockClients.clear();
142
- });
143
- describe('constructor', () => {
144
- it('should create an ExtensionsWebSocket instance', () => {
145
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
146
- expect(extensionsWebSocket).toBeDefined();
147
- });
148
- });
149
- describe('setupUpgradeHandler', () => {
150
- it('should reject connections from non-allowed origins', () => {
151
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
152
- const mockSocket = {
153
- destroy: vi.fn(),
154
- };
155
- const mockRequest = {
156
- headers: {
157
- origin: 'https://evil.com',
158
- },
159
- };
160
- mockHttpServer.emit('upgrade', mockRequest, mockSocket, Buffer.from([]));
161
- expect(mockSocket.destroy).toHaveBeenCalled();
162
- expect(devServerState.logger.debug).toHaveBeenCalledWith('Rejected WebSocket: https://evil.com');
163
- });
164
- it('should accept connections from allowed origins', () => {
165
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
166
- simulateClientConnection('http://localhost');
167
- expect(extensionsWebSocket.clientCount).toBe(1);
168
- });
169
- });
170
- describe('broadcast', () => {
171
- it('should log when no clients are connected', () => {
172
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
173
- extensionsWebSocket.broadcast({ event: 'test' });
174
- expect(devServerState.logger.debug).toHaveBeenCalledWith('No clients connected, message not sent');
175
- });
176
- it('should send messages to all connected clients', () => {
177
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
178
- const { client: client1 } = simulateClientConnection();
179
- const { client: client2 } = simulateClientConnection();
180
- extensionsWebSocket.broadcast({ event: 'test', data: 'hello' });
181
- expect(client1.send).toHaveBeenCalledWith(JSON.stringify({ event: 'test', data: 'hello' }));
182
- expect(client2.send).toHaveBeenCalledWith(JSON.stringify({ event: 'test', data: 'hello' }));
183
- });
184
- it('should handle send failures gracefully', () => {
185
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
186
- const { client } = simulateClientConnection();
187
- vi.mocked(client.send).mockImplementation(() => {
188
- throw new Error('Send failed');
189
- });
190
- extensionsWebSocket.broadcast({ event: 'test' });
191
- expect(devServerState.logger.warn).toHaveBeenCalledWith('Sent to 0 clients, 1 failed');
192
- });
193
- });
194
- describe('onConnection', () => {
195
- it('should register connection handler', () => {
196
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
197
- let connectionHandlerCalled = false;
198
- extensionsWebSocket.onConnection(() => {
199
- connectionHandlerCalled = true;
200
- });
201
- simulateClientConnection();
202
- expect(connectionHandlerCalled).toBe(true);
203
- });
204
- });
205
- describe('clientCount', () => {
206
- it('should return 0 when no clients are connected', () => {
207
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
208
- expect(extensionsWebSocket.clientCount).toBe(0);
209
- });
210
- it('should return correct count of connected clients', () => {
211
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
212
- simulateClientConnection();
213
- simulateClientConnection();
214
- expect(extensionsWebSocket.clientCount).toBe(2);
215
- });
216
- });
217
- describe('keepAlive', () => {
218
- it('should terminate clients that do not respond to ping', () => {
219
- let keepAliveCallback;
220
- const setIntervalSpy = vi
221
- .spyOn(global, 'setInterval')
222
- .mockImplementation((fn) => {
223
- keepAliveCallback = fn;
224
- return MOCK_INTERVAL_ID;
225
- });
226
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
227
- const { client } = simulateClientConnection();
228
- // First keepAlive call: marks client as not alive and sends ping
229
- keepAliveCallback();
230
- // Second keepAlive call: should terminate since client didn't respond
231
- keepAliveCallback();
232
- expect(client.terminate).toHaveBeenCalled();
233
- setIntervalSpy.mockRestore();
234
- });
235
- });
236
- describe('client handlers', () => {
237
- it('should log client errors', () => {
238
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
239
- const { client } = simulateClientConnection();
240
- client.emit('error', new Error('Test error'));
241
- expect(devServerState.logger.debug).toHaveBeenCalledWith('Client error: Test error');
242
- });
243
- it('should log client disconnections', () => {
244
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
245
- const { client } = simulateClientConnection();
246
- client.close();
247
- const debugCalls = vi.mocked(devServerState.logger.debug).mock.calls;
248
- const hasDisconnectLog = debugCalls.some((call) => call[0].includes('Client disconnected'));
249
- expect(hasDisconnectLog).toBe(true);
250
- });
251
- });
252
- describe('close', () => {
253
- it('should terminate all clients before closing', async () => {
254
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
255
- const { client: client1 } = simulateClientConnection();
256
- const { client: client2 } = simulateClientConnection();
257
- expect(extensionsWebSocket.clientCount).toBe(2);
258
- await extensionsWebSocket.close();
259
- expect(client1.terminate).toHaveBeenCalled();
260
- expect(client2.terminate).toHaveBeenCalled();
261
- expect(extensionsWebSocket.clientCount).toBe(0);
262
- });
263
- it('should close the WebSocket server after clients disconnect', async () => {
264
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
265
- const { client } = simulateClientConnection();
266
- expect(extensionsWebSocket.clientCount).toBe(1);
267
- client.close();
268
- await extensionsWebSocket.close();
269
- expect(extensionsWebSocket.clientCount).toBe(0);
270
- });
271
- it('should stop keep-alive mechanism after close', async () => {
272
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
273
- const { client } = simulateClientConnection();
274
- const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
275
- client.close();
276
- await extensionsWebSocket.close();
277
- expect(clearIntervalSpy).toHaveBeenCalled();
278
- clearIntervalSpy.mockRestore();
279
- });
280
- it('should reject when close is called multiple times', async () => {
281
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
282
- await extensionsWebSocket.close();
283
- await expect(extensionsWebSocket.close()).rejects.toThrow('The server is not running');
284
- });
285
- it('should not broadcast after close', async () => {
286
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
287
- const { client } = simulateClientConnection();
288
- client.close();
289
- await extensionsWebSocket.close();
290
- extensionsWebSocket.broadcast({ event: 'test' });
291
- expect(devServerState.logger.debug).toHaveBeenCalledWith('No clients connected, message not sent');
292
- });
293
- });
294
- describe('error handlers', () => {
295
- it('should log WebSocket server errors', () => {
296
- extensionsWebSocket = new ExtensionsWebSocket(mockHttpServer, devServerState);
297
- const testError = new Error('Server error');
298
- const errorHandler = vi.mocked(mockWss.on).mock.calls.find((call) => call[0] === 'error')?.[1];
299
- errorHandler?.(testError);
300
- expect(devServerState.logger.error).toHaveBeenCalledWith('WebSocket server error: Error: Server error');
301
- });
302
- });
303
- });
304
- });
@@ -1 +0,0 @@
1
- export {};