@teardown/cli 1.2.28 → 1.2.30

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 (26) hide show
  1. package/dist/modules/dev/dev-menu/keyboard-handler.d.ts +1 -0
  2. package/dist/modules/dev/dev-menu/keyboard-handler.js +9 -1
  3. package/dist/modules/dev/dev-server/cdp/index.d.ts +2 -0
  4. package/dist/modules/dev/dev-server/cdp/index.js +18 -0
  5. package/dist/modules/dev/dev-server/cdp/types.d.ts +107 -0
  6. package/dist/modules/dev/dev-server/cdp/types.js +2 -0
  7. package/dist/modules/dev/dev-server/dev-server.d.ts +2 -0
  8. package/dist/modules/dev/dev-server/dev-server.js +48 -25
  9. package/dist/modules/dev/dev-server/inspector/device.d.ts +46 -0
  10. package/dist/modules/dev/dev-server/inspector/device.event-reporter.d.ts +37 -0
  11. package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +165 -0
  12. package/dist/modules/dev/dev-server/inspector/device.js +577 -0
  13. package/dist/modules/dev/dev-server/inspector/inspector.d.ts +27 -0
  14. package/dist/modules/dev/dev-server/inspector/inspector.js +205 -0
  15. package/dist/modules/dev/dev-server/inspector/types.d.ts +156 -0
  16. package/dist/modules/dev/dev-server/inspector/types.js +2 -0
  17. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.d.ts +14 -0
  18. package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +61 -0
  19. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.d.ts +19 -0
  20. package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +64 -0
  21. package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +1 -2
  22. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.d.ts +3 -0
  23. package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +7 -1
  24. package/dist/modules/dev/terminal/terminal.reporter.d.ts +3 -1
  25. package/dist/modules/dev/terminal/terminal.reporter.js +3 -0
  26. package/package.json +4 -4
@@ -0,0 +1,577 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Device = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_url_1 = require("node:url");
10
+ const ws_1 = __importDefault(require("ws"));
11
+ const device_event_reporter_1 = require("./device.event-reporter");
12
+ const debug = require("debug")("Metro:InspectorProxy");
13
+ const PAGES_POLLING_INTERVAL = 1000;
14
+ // Constants for host rewriting
15
+ const REWRITE_HOSTS_TO_LOCALHOST = [
16
+ "127.0.0.1",
17
+ "10.0.2.2",
18
+ "10.0.3.2",
19
+ ];
20
+ const FILE_PREFIX = "file://";
21
+ const REACT_NATIVE_RELOADABLE_PAGE_ID = "-1";
22
+ class Device {
23
+ id;
24
+ name;
25
+ app;
26
+ messageFromDeviceQueue = Promise.resolve();
27
+ deviceSocket;
28
+ pages = new Map();
29
+ debuggerConnection = null;
30
+ lastConnectedLegacyReactNativePage = null;
31
+ isLegacyPageReloading = false;
32
+ lastGetPagesMessage = "";
33
+ scriptIdToSourcePathMapping = new Map();
34
+ projectRoot;
35
+ deviceEventReporter;
36
+ pagesPollingIntervalId;
37
+ createCustomMessageHandler;
38
+ connectedPageIds = new Set();
39
+ constructor(id, name, app, socket, projectRoot, eventReporter) {
40
+ this.id = id;
41
+ this.name = name;
42
+ this.app = app;
43
+ this.deviceSocket = socket;
44
+ this.projectRoot = projectRoot;
45
+ this.deviceEventReporter =
46
+ eventReporter != null
47
+ ? new device_event_reporter_1.DeviceEventReporter(eventReporter, {
48
+ deviceId: id,
49
+ deviceName: name,
50
+ appId: app,
51
+ })
52
+ : null;
53
+ this.createCustomMessageHandler = null;
54
+ // Setup message handling
55
+ this.deviceSocket.on("message", (message) => {
56
+ this.messageFromDeviceQueue = this.messageFromDeviceQueue
57
+ .then(async () => {
58
+ const parsedMessage = JSON.parse(message);
59
+ if (parsedMessage.event === "getPages") {
60
+ if (message !== this.lastGetPagesMessage) {
61
+ debug(`(Debugger) (Proxy) <- (Device), getPages ping has changed: ${message}`);
62
+ this.lastGetPagesMessage = message;
63
+ }
64
+ }
65
+ else {
66
+ debug(`(Debugger) (Proxy) <- (Device): ${message}`);
67
+ }
68
+ await this.handleMessageFromDevice(parsedMessage);
69
+ })
70
+ .catch((error) => {
71
+ debug("%O\nHandling device message: %s", error, message);
72
+ try {
73
+ this.deviceEventReporter?.logProxyMessageHandlingError("device", error, message);
74
+ }
75
+ catch (loggingError) {
76
+ debug("Error logging message handling error to reporter: %O", loggingError);
77
+ }
78
+ });
79
+ });
80
+ // Setup polling
81
+ this.pagesPollingIntervalId = setInterval(() => this.sendMessageToDevice({ event: "getPages" }), PAGES_POLLING_INTERVAL);
82
+ // Handle socket close
83
+ this.deviceSocket.on("close", () => {
84
+ if (socket === this.deviceSocket) {
85
+ this.deviceEventReporter?.logDisconnection("device");
86
+ this.terminateDebuggerConnection();
87
+ clearInterval(this.pagesPollingIntervalId);
88
+ }
89
+ });
90
+ }
91
+ terminateDebuggerConnection() {
92
+ const debuggerConnection = this.debuggerConnection;
93
+ if (debuggerConnection) {
94
+ this.sendDisconnectEventToDevice(this.mapToDevicePageId(debuggerConnection.pageId));
95
+ debuggerConnection.socket.close();
96
+ this.debuggerConnection = null;
97
+ }
98
+ }
99
+ dangerouslyRecreateDevice(id, name, app, socket, projectRoot, eventReporter) {
100
+ invariant(id === this.id, "dangerouslyRecreateDevice() can only be used for the same device ID");
101
+ const oldDebugger = this.debuggerConnection;
102
+ if (this.app !== app || this.name !== name) {
103
+ this.deviceSocket.close();
104
+ this.terminateDebuggerConnection();
105
+ }
106
+ this.debuggerConnection = null;
107
+ if (oldDebugger) {
108
+ oldDebugger.socket.removeAllListeners();
109
+ this.deviceSocket.close();
110
+ this.handleDebuggerConnection(oldDebugger.socket, oldDebugger.pageId, {
111
+ userAgent: oldDebugger.userAgent,
112
+ });
113
+ }
114
+ this.id = id;
115
+ this.name = name;
116
+ this.app = app;
117
+ this.deviceSocket = socket;
118
+ this.projectRoot = projectRoot;
119
+ this.deviceEventReporter = eventReporter
120
+ ? new device_event_reporter_1.DeviceEventReporter(eventReporter, {
121
+ deviceId: id,
122
+ deviceName: name,
123
+ appId: app,
124
+ })
125
+ : null;
126
+ }
127
+ getName() {
128
+ return this.name;
129
+ }
130
+ getApp() {
131
+ return this.app;
132
+ }
133
+ getPagesList() {
134
+ if (this.lastConnectedLegacyReactNativePage) {
135
+ return [...this.pages.values(), this.createSyntheticPage()];
136
+ }
137
+ return [...this.pages.values()];
138
+ }
139
+ handleDebuggerConnection(socket, pageId, metadata) {
140
+ const page = pageId === REACT_NATIVE_RELOADABLE_PAGE_ID
141
+ ? this.createSyntheticPage()
142
+ : this.pages.get(pageId);
143
+ if (!page) {
144
+ debug(`Got new debugger connection for page ${pageId} of ${this.name}, but no such page exists`);
145
+ socket.close();
146
+ return;
147
+ }
148
+ this.deviceEventReporter?.logDisconnection("debugger");
149
+ this.terminateDebuggerConnection();
150
+ this.deviceEventReporter?.logConnection("debugger", {
151
+ pageId,
152
+ frontendUserAgent: metadata.userAgent,
153
+ });
154
+ const debuggerInfo = {
155
+ socket,
156
+ prependedFilePrefix: false,
157
+ pageId,
158
+ userAgent: metadata.userAgent,
159
+ customHandler: null,
160
+ };
161
+ this.debuggerConnection = debuggerInfo;
162
+ if (this.debuggerConnection && this.createCustomMessageHandler) {
163
+ this.debuggerConnection.customHandler = this.createCustomMessageHandler({
164
+ page,
165
+ debugger: {
166
+ userAgent: debuggerInfo.userAgent,
167
+ sendMessage: (message) => {
168
+ try {
169
+ const payload = JSON.stringify(message);
170
+ debug(`(Debugger) <- (Proxy) (Device): ${payload}`);
171
+ socket.send(payload);
172
+ }
173
+ catch { }
174
+ },
175
+ },
176
+ device: {
177
+ appId: this.app,
178
+ id: this.id,
179
+ name: this.name,
180
+ sendMessage: (message) => {
181
+ try {
182
+ const payload = JSON.stringify({
183
+ event: "wrappedEvent",
184
+ payload: {
185
+ pageId: this.mapToDevicePageId(pageId),
186
+ wrappedEvent: JSON.stringify(message),
187
+ },
188
+ });
189
+ debug(`(Debugger) -> (Proxy) (Device): ${payload}`);
190
+ this.deviceSocket.send(payload);
191
+ }
192
+ catch { }
193
+ },
194
+ },
195
+ });
196
+ }
197
+ this.sendConnectEventToDevice(this.mapToDevicePageId(pageId));
198
+ socket.on("message", (message) => {
199
+ debug(`(Debugger) -> (Proxy) (Device): ${message}`);
200
+ const debuggerRequest = JSON.parse(message);
201
+ this.deviceEventReporter?.logRequest(debuggerRequest, "debugger", {
202
+ pageId: this.debuggerConnection?.pageId ?? null,
203
+ frontendUserAgent: metadata.userAgent,
204
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(this.debuggerConnection?.pageId ?? null),
205
+ });
206
+ if (this.debuggerConnection?.customHandler?.handleDebuggerMessage(debuggerRequest) === true) {
207
+ return;
208
+ }
209
+ if (!this.pageHasCapability(page, "nativeSourceCodeFetching")) {
210
+ const processedReq = this.interceptClientMessageForSourceFetching(debuggerRequest, debuggerInfo, socket);
211
+ if (processedReq) {
212
+ this.sendMessageToDevice({
213
+ event: "wrappedEvent",
214
+ payload: {
215
+ pageId: this.mapToDevicePageId(pageId),
216
+ wrappedEvent: JSON.stringify(processedReq),
217
+ },
218
+ });
219
+ }
220
+ }
221
+ });
222
+ socket.on("close", () => {
223
+ debug(`Debugger for page ${pageId} and ${this.name} disconnected.`);
224
+ this.deviceEventReporter?.logDisconnection("debugger");
225
+ if (this.debuggerConnection?.socket === socket) {
226
+ this.terminateDebuggerConnection();
227
+ }
228
+ });
229
+ const sendFunc = socket.send.bind(socket);
230
+ socket.send = (message) => {
231
+ debug(`(Debugger) <- (Proxy) (Device): ${message}`);
232
+ return sendFunc(message);
233
+ };
234
+ }
235
+ sendConnectEventToDevice(devicePageId) {
236
+ if (this.connectedPageIds.has(devicePageId)) {
237
+ return;
238
+ }
239
+ this.connectedPageIds.add(devicePageId);
240
+ this.sendMessageToDevice({
241
+ event: "connect",
242
+ payload: { pageId: devicePageId },
243
+ });
244
+ }
245
+ sendDisconnectEventToDevice(devicePageId) {
246
+ if (!this.connectedPageIds.has(devicePageId)) {
247
+ return;
248
+ }
249
+ this.connectedPageIds.delete(devicePageId);
250
+ this.sendMessageToDevice({
251
+ event: "disconnect",
252
+ payload: { pageId: devicePageId },
253
+ });
254
+ }
255
+ pageHasCapability(page, flag) {
256
+ return page.capabilities[flag] === true;
257
+ }
258
+ createSyntheticPage() {
259
+ return {
260
+ id: REACT_NATIVE_RELOADABLE_PAGE_ID,
261
+ title: "React Native Experimental (Improved Chrome Reloads)",
262
+ vm: "don't use",
263
+ app: this.app,
264
+ capabilities: {},
265
+ };
266
+ }
267
+ async handleMessageFromDevice(message) {
268
+ if (message.event === "getPages") {
269
+ this.pages = new Map(message.payload.map((page) => {
270
+ const { capabilities = {}, ...rest } = page;
271
+ return [
272
+ rest.id,
273
+ {
274
+ ...rest,
275
+ capabilities,
276
+ },
277
+ ];
278
+ }));
279
+ for (const page of this.pages.values()) {
280
+ if (this.pageHasCapability(page, "nativePageReloads")) {
281
+ continue;
282
+ }
283
+ if (page.title.includes("React")) {
284
+ if (page.id !== this.lastConnectedLegacyReactNativePage?.id) {
285
+ this.newLegacyReactNativePage(page);
286
+ break;
287
+ }
288
+ }
289
+ }
290
+ }
291
+ else if (message.event === "disconnect") {
292
+ const pageId = message.payload.pageId;
293
+ const page = this.pages.get(pageId);
294
+ if (page && this.pageHasCapability(page, "nativePageReloads")) {
295
+ return;
296
+ }
297
+ const debuggerSocket = this.debuggerConnection?.socket;
298
+ if (debuggerSocket && debuggerSocket.readyState === ws_1.default.OPEN) {
299
+ if (this.debuggerConnection &&
300
+ this.debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID) {
301
+ debug(`Legacy page ${pageId} is reloading.`);
302
+ debuggerSocket.send(JSON.stringify({ method: "reload" }));
303
+ }
304
+ }
305
+ }
306
+ else if (message.event === "wrappedEvent") {
307
+ if (!this.debuggerConnection) {
308
+ return;
309
+ }
310
+ const debuggerSocket = this.debuggerConnection.socket;
311
+ if (!debuggerSocket || debuggerSocket.readyState !== ws_1.default.OPEN) {
312
+ return;
313
+ }
314
+ const parsedPayload = JSON.parse(message.payload.wrappedEvent);
315
+ const pageId = this.debuggerConnection.pageId;
316
+ if ("id" in parsedPayload) {
317
+ this.deviceEventReporter?.logResponse(parsedPayload, "device", {
318
+ pageId,
319
+ frontendUserAgent: this.debuggerConnection.userAgent,
320
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(pageId),
321
+ });
322
+ }
323
+ if (this.debuggerConnection.customHandler?.handleDeviceMessage(parsedPayload) === true) {
324
+ return;
325
+ }
326
+ await this.processMessageFromDeviceLegacy(parsedPayload, this.debuggerConnection, pageId);
327
+ debuggerSocket.send(JSON.stringify(parsedPayload));
328
+ }
329
+ }
330
+ sendMessageToDevice(message) {
331
+ try {
332
+ if (message.event !== "getPages") {
333
+ debug(`(Debugger) (Proxy) -> (Device): ${JSON.stringify(message)}`);
334
+ }
335
+ this.deviceSocket.send(JSON.stringify(message));
336
+ }
337
+ catch (error) { }
338
+ }
339
+ newLegacyReactNativePage(page) {
340
+ debug(`React Native page updated to ${page.id}`);
341
+ if (!this.debuggerConnection ||
342
+ this.debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID) {
343
+ this.lastConnectedLegacyReactNativePage = page;
344
+ return;
345
+ }
346
+ const oldPageId = this.lastConnectedLegacyReactNativePage?.id;
347
+ this.lastConnectedLegacyReactNativePage = page;
348
+ this.isLegacyPageReloading = true;
349
+ if (oldPageId != null) {
350
+ this.sendDisconnectEventToDevice(oldPageId);
351
+ }
352
+ this.sendConnectEventToDevice(page.id);
353
+ const toSend = [
354
+ { method: "Runtime.enable", id: 1e9 },
355
+ { method: "Debugger.enable", id: 1e9 },
356
+ ];
357
+ for (const message of toSend) {
358
+ const pageId = this.debuggerConnection?.pageId ?? null;
359
+ this.deviceEventReporter?.logRequest(message, "proxy", {
360
+ pageId,
361
+ frontendUserAgent: this.debuggerConnection?.userAgent ?? null,
362
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(pageId),
363
+ });
364
+ this.sendMessageToDevice({
365
+ event: "wrappedEvent",
366
+ payload: {
367
+ pageId: this.mapToDevicePageId(page.id),
368
+ wrappedEvent: JSON.stringify(message),
369
+ },
370
+ });
371
+ }
372
+ }
373
+ async processMessageFromDeviceLegacy(payload, debuggerInfo, pageId) {
374
+ const page = pageId != null ? this.pages.get(pageId) : null;
375
+ if ((!page || !this.pageHasCapability(page, "nativeSourceCodeFetching")) &&
376
+ payload.method === "Debugger.scriptParsed" &&
377
+ // @ts-ignore
378
+ payload.params != null) {
379
+ // @ts-ignore
380
+ const params = payload.params;
381
+ if ("sourceMapURL" in params) {
382
+ for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
383
+ if (params.sourceMapURL.includes(hostToRewrite)) {
384
+ // @ts-ignore
385
+ payload.params.sourceMapURL = params.sourceMapURL.replace(hostToRewrite, "localhost");
386
+ debuggerInfo.originalSourceURLAddress = hostToRewrite;
387
+ }
388
+ }
389
+ const sourceMapURL = this.tryParseHTTPURL(params.sourceMapURL);
390
+ if (sourceMapURL) {
391
+ try {
392
+ const sourceMap = await this.fetchText(sourceMapURL);
393
+ // @ts-ignore
394
+ payload.params.sourceMapURL = `data:application/json;charset=utf-8;base64,${Buffer.from(sourceMap).toString("base64")}`;
395
+ }
396
+ catch (exception) {
397
+ const exceptionMessage = exception instanceof Error
398
+ ? exception.message
399
+ : String(exception);
400
+ this.sendErrorToDebugger(`Failed to fetch source map ${params.sourceMapURL}: ${exceptionMessage}`);
401
+ }
402
+ }
403
+ }
404
+ if ("url" in params) {
405
+ for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
406
+ if (params?.url?.includes(hostToRewrite)) {
407
+ payload.params.url = params.url.replace(hostToRewrite, "localhost");
408
+ debuggerInfo.originalSourceURLAddress = hostToRewrite;
409
+ }
410
+ }
411
+ if (payload.params.url.match(/^[0-9a-z]+$/)) {
412
+ payload.params.url = FILE_PREFIX + payload.params.url;
413
+ debuggerInfo.prependedFilePrefix = true;
414
+ }
415
+ if (params.scriptId != null) {
416
+ this.scriptIdToSourcePathMapping.set(params.scriptId, params.url);
417
+ }
418
+ }
419
+ }
420
+ if (payload.method === "Runtime.executionContextCreated" &&
421
+ this.isLegacyPageReloading) {
422
+ debuggerInfo.socket.send(JSON.stringify({ method: "Runtime.executionContextsCleared" }));
423
+ const resumeMessage = { method: "Debugger.resume", id: 0 };
424
+ this.deviceEventReporter?.logRequest(resumeMessage, "proxy", {
425
+ pageId: this.debuggerConnection?.pageId ?? null,
426
+ frontendUserAgent: this.debuggerConnection?.userAgent ?? null,
427
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(this.debuggerConnection?.pageId ?? null),
428
+ });
429
+ this.sendMessageToDevice({
430
+ event: "wrappedEvent",
431
+ payload: {
432
+ pageId: this.mapToDevicePageId(debuggerInfo.pageId),
433
+ wrappedEvent: JSON.stringify(resumeMessage),
434
+ },
435
+ });
436
+ this.isLegacyPageReloading = false;
437
+ }
438
+ }
439
+ interceptClientMessageForSourceFetching(req, debuggerInfo, socket) {
440
+ switch (req.method) {
441
+ case "Debugger.setBreakpointByUrl":
442
+ return this.processDebuggerSetBreakpointByUrl(req, debuggerInfo);
443
+ case "Debugger.getScriptSource":
444
+ this.processDebuggerGetScriptSource(req, socket);
445
+ return null;
446
+ default:
447
+ return req;
448
+ }
449
+ }
450
+ processDebuggerSetBreakpointByUrl(req, debuggerInfo) {
451
+ if (debuggerInfo.originalSourceURLAddress != null) {
452
+ const processedReq = { ...req, params: { ...req.params } };
453
+ if (processedReq.params.url != null) {
454
+ processedReq.params.url = processedReq.params.url.replace("localhost", debuggerInfo.originalSourceURLAddress);
455
+ if (processedReq.params.url?.startsWith(FILE_PREFIX) &&
456
+ debuggerInfo.prependedFilePrefix) {
457
+ processedReq.params.url = processedReq.params.url.slice(FILE_PREFIX.length);
458
+ }
459
+ }
460
+ if (processedReq.params.urlRegex != null) {
461
+ processedReq.params.urlRegex = processedReq.params.urlRegex.replace(/localhost/g, debuggerInfo.originalSourceURLAddress);
462
+ }
463
+ return processedReq;
464
+ }
465
+ return req;
466
+ }
467
+ processDebuggerGetScriptSource(req, socket) {
468
+ const sendSuccessResponse = (scriptSource) => {
469
+ const result = { scriptSource };
470
+ const response = {
471
+ id: req.id,
472
+ result,
473
+ };
474
+ socket.send(JSON.stringify(response));
475
+ const pageId = this.debuggerConnection?.pageId ?? null;
476
+ this.deviceEventReporter?.logResponse(response, "proxy", {
477
+ pageId,
478
+ frontendUserAgent: this.debuggerConnection?.userAgent ?? null,
479
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(pageId),
480
+ });
481
+ };
482
+ const sendErrorResponse = (error) => {
483
+ const result = { error: { message: error } };
484
+ const response = { id: req.id, result };
485
+ socket.send(JSON.stringify(response));
486
+ this.sendErrorToDebugger(error);
487
+ const pageId = this.debuggerConnection?.pageId ?? null;
488
+ this.deviceEventReporter?.logResponse(response, "proxy", {
489
+ pageId,
490
+ frontendUserAgent: this.debuggerConnection?.userAgent ?? null,
491
+ prefersFuseboxFrontend: this.isPageFuseboxFrontend(pageId),
492
+ });
493
+ };
494
+ const pathToSource = this.scriptIdToSourcePathMapping.get(req.params.scriptId);
495
+ if (pathToSource != null) {
496
+ const httpURL = this.tryParseHTTPURL(pathToSource);
497
+ if (httpURL) {
498
+ this.fetchText(httpURL).then((text) => sendSuccessResponse(text), (err) => sendErrorResponse(`Failed to fetch source url ${pathToSource}: ${err.message}`));
499
+ }
500
+ else {
501
+ let file;
502
+ try {
503
+ file = node_fs_1.default.readFileSync(node_path_1.default.resolve(this.projectRoot, pathToSource), "utf8");
504
+ sendSuccessResponse(file);
505
+ }
506
+ catch (err) {
507
+ const exceptionMessage = err instanceof Error ? err.message : String(err);
508
+ sendErrorResponse(`Failed to fetch source file ${pathToSource}: ${exceptionMessage}`);
509
+ }
510
+ }
511
+ }
512
+ }
513
+ mapToDevicePageId(pageId) {
514
+ if (pageId === REACT_NATIVE_RELOADABLE_PAGE_ID &&
515
+ this.lastConnectedLegacyReactNativePage != null) {
516
+ return this.lastConnectedLegacyReactNativePage.id;
517
+ }
518
+ return pageId;
519
+ }
520
+ tryParseHTTPURL(url) {
521
+ let parsedURL = null;
522
+ try {
523
+ parsedURL = new node_url_1.URL(url);
524
+ }
525
+ catch { }
526
+ const protocol = parsedURL?.protocol;
527
+ if (protocol !== "http:" && protocol !== "https:") {
528
+ parsedURL = null;
529
+ }
530
+ return parsedURL;
531
+ }
532
+ async fetchText(url) {
533
+ const response = await fetch(url.toString());
534
+ if (!response.ok) {
535
+ throw new Error(`HTTP ${response.status} ${response.statusText}`);
536
+ }
537
+ const text = await response.text();
538
+ if (text.length > 350000000) {
539
+ throw new Error("file too large to fetch via HTTP");
540
+ }
541
+ return text;
542
+ }
543
+ sendErrorToDebugger(message) {
544
+ const debuggerSocket = this.debuggerConnection?.socket;
545
+ if (debuggerSocket && debuggerSocket.readyState === ws_1.default.OPEN) {
546
+ debuggerSocket.send(JSON.stringify({
547
+ method: "Runtime.consoleAPICalled",
548
+ params: {
549
+ args: [
550
+ {
551
+ type: "string",
552
+ value: message,
553
+ },
554
+ ],
555
+ executionContextId: 0,
556
+ type: "error",
557
+ },
558
+ }));
559
+ }
560
+ }
561
+ isPageFuseboxFrontend(pageId) {
562
+ const page = pageId == null ? null : this.pages.get(pageId);
563
+ if (page == null) {
564
+ return null;
565
+ }
566
+ return this.pageHasCapability(page, "prefersFuseboxFrontend");
567
+ }
568
+ dangerouslyGetSocket() {
569
+ return this.deviceSocket;
570
+ }
571
+ }
572
+ exports.Device = Device;
573
+ const invariant = (condition, message) => {
574
+ if (!condition) {
575
+ throw new Error(message);
576
+ }
577
+ };
@@ -0,0 +1,27 @@
1
+ import { WebSocketServer } from "ws";
2
+ import type { IncomingMessage, ServerResponse } from "node:http";
3
+ import type { EventReporter, PageDescription } from "./types";
4
+ import type { CDPAdapter } from "../cdp/cdp.adapter";
5
+ export interface InspectorOptions {
6
+ projectRoot: string;
7
+ serverBaseUrl: string;
8
+ eventReporter?: EventReporter;
9
+ cdpAdapter?: CDPAdapter;
10
+ }
11
+ export declare class Inspector {
12
+ private devices;
13
+ private deviceCounter;
14
+ private readonly projectRoot;
15
+ private readonly serverBaseUrl;
16
+ private readonly eventReporter?;
17
+ private readonly cdpAdapter?;
18
+ constructor(options: InspectorOptions);
19
+ getPageDescriptions(): PageDescription[];
20
+ handleHttpRequest: (req: IncomingMessage, res: ServerResponse, next: (error?: Error) => void) => void;
21
+ createWebSocketServers(): Record<string, WebSocketServer>;
22
+ private createPageDescription;
23
+ private createDeviceWebSocketServer;
24
+ private createDebuggerWebSocketServer;
25
+ private setupHeartbeat;
26
+ private sendJsonResponse;
27
+ }