@depup/react-native__dev-middleware 0.84.1-depup.1

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 (63) hide show
  1. package/README.md +38 -0
  2. package/changes.json +38 -0
  3. package/dist/createDevMiddleware.d.ts +62 -0
  4. package/dist/createDevMiddleware.js +140 -0
  5. package/dist/createDevMiddleware.js.flow +72 -0
  6. package/dist/index.d.ts +23 -0
  7. package/dist/index.js +26 -0
  8. package/dist/index.js.flow +24 -0
  9. package/dist/inspector-proxy/CdpDebugLogging.d.ts +20 -0
  10. package/dist/inspector-proxy/CdpDebugLogging.js +117 -0
  11. package/dist/inspector-proxy/CdpDebugLogging.js.flow +20 -0
  12. package/dist/inspector-proxy/CustomMessageHandler.d.ts +48 -0
  13. package/dist/inspector-proxy/CustomMessageHandler.js +1 -0
  14. package/dist/inspector-proxy/CustomMessageHandler.js.flow +54 -0
  15. package/dist/inspector-proxy/Device.d.ts +62 -0
  16. package/dist/inspector-proxy/Device.js +810 -0
  17. package/dist/inspector-proxy/Device.js.flow +70 -0
  18. package/dist/inspector-proxy/DeviceEventReporter.d.ts +54 -0
  19. package/dist/inspector-proxy/DeviceEventReporter.js +194 -0
  20. package/dist/inspector-proxy/DeviceEventReporter.js.flow +62 -0
  21. package/dist/inspector-proxy/EventLoopPerfTracker.d.ts +31 -0
  22. package/dist/inspector-proxy/EventLoopPerfTracker.js +50 -0
  23. package/dist/inspector-proxy/EventLoopPerfTracker.js.flow +34 -0
  24. package/dist/inspector-proxy/InspectorProxy.d.ts +53 -0
  25. package/dist/inspector-proxy/InspectorProxy.js +477 -0
  26. package/dist/inspector-proxy/InspectorProxy.js.flow +62 -0
  27. package/dist/inspector-proxy/InspectorProxyHeartbeat.d.ts +24 -0
  28. package/dist/inspector-proxy/InspectorProxyHeartbeat.js +64 -0
  29. package/dist/inspector-proxy/InspectorProxyHeartbeat.js.flow +25 -0
  30. package/dist/inspector-proxy/cdp-types/messages.d.ts +41 -0
  31. package/dist/inspector-proxy/cdp-types/messages.js +1 -0
  32. package/dist/inspector-proxy/cdp-types/messages.js.flow +54 -0
  33. package/dist/inspector-proxy/cdp-types/protocol.d.ts +106 -0
  34. package/dist/inspector-proxy/cdp-types/protocol.js +1 -0
  35. package/dist/inspector-proxy/cdp-types/protocol.js.flow +124 -0
  36. package/dist/inspector-proxy/types.d.ts +115 -0
  37. package/dist/inspector-proxy/types.js +1 -0
  38. package/dist/inspector-proxy/types.js.flow +152 -0
  39. package/dist/middleware/openDebuggerMiddleware.d.ts +36 -0
  40. package/dist/middleware/openDebuggerMiddleware.js +216 -0
  41. package/dist/middleware/openDebuggerMiddleware.js.flow +36 -0
  42. package/dist/types/BrowserLauncher.d.ts +62 -0
  43. package/dist/types/BrowserLauncher.js +1 -0
  44. package/dist/types/BrowserLauncher.js.flow +66 -0
  45. package/dist/types/EventReporter.d.ts +124 -0
  46. package/dist/types/EventReporter.js +1 -0
  47. package/dist/types/EventReporter.js.flow +151 -0
  48. package/dist/types/Experiments.d.ts +30 -0
  49. package/dist/types/Experiments.js +1 -0
  50. package/dist/types/Experiments.js.flow +34 -0
  51. package/dist/types/Logger.d.ts +15 -0
  52. package/dist/types/Logger.js +1 -0
  53. package/dist/types/Logger.js.flow +16 -0
  54. package/dist/utils/DefaultBrowserLauncher.d.ts +30 -0
  55. package/dist/utils/DefaultBrowserLauncher.js +57 -0
  56. package/dist/utils/DefaultBrowserLauncher.js.flow +29 -0
  57. package/dist/utils/getBaseUrlFromRequest.d.ts +14 -0
  58. package/dist/utils/getBaseUrlFromRequest.js +19 -0
  59. package/dist/utils/getBaseUrlFromRequest.js.flow +17 -0
  60. package/dist/utils/getDevToolsFrontendUrl.d.ts +29 -0
  61. package/dist/utils/getDevToolsFrontendUrl.js +58 -0
  62. package/dist/utils/getDevToolsFrontendUrl.js.flow +29 -0
  63. package/package.json +97 -0
@@ -0,0 +1,810 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+ exports.default = exports.WS_CLOSE_REASON = void 0;
7
+ var _CdpDebugLogging = _interopRequireDefault(require("./CdpDebugLogging"));
8
+ var _DeviceEventReporter = _interopRequireDefault(
9
+ require("./DeviceEventReporter"),
10
+ );
11
+ var _invariant = _interopRequireDefault(require("invariant"));
12
+ var _ws = _interopRequireDefault(require("ws"));
13
+ function _interopRequireDefault(e) {
14
+ return e && e.__esModule ? e : { default: e };
15
+ }
16
+ const debug = require("debug")("Metro:InspectorProxy");
17
+ const PAGES_POLLING_INTERVAL = 1000;
18
+ const WS_CLOSURE_CODE = {
19
+ NORMAL: 1000,
20
+ INTERNAL_ERROR: 1011,
21
+ };
22
+ const WS_CLOSE_REASON = (exports.WS_CLOSE_REASON = {
23
+ PAGE_NOT_FOUND: "[PAGE_NOT_FOUND] Debugger page not found",
24
+ CONNECTION_LOST: "[CONNECTION_LOST] Connection lost to corresponding device",
25
+ RECREATING_DEVICE: "[RECREATING_DEVICE] Recreating device connection",
26
+ NEW_DEBUGGER_OPENED:
27
+ "[NEW_DEBUGGER_OPENED] New debugger opened for the same app instance",
28
+ });
29
+ const FILE_PREFIX = "file://";
30
+ let fuseboxConsoleNoticeLogged = false;
31
+ const REACT_NATIVE_RELOADABLE_PAGE_ID = "-1";
32
+ class Device {
33
+ #id;
34
+ #name;
35
+ #app;
36
+ #deviceSocket;
37
+ #pages = new Map();
38
+ #debuggerConnection = null;
39
+ #lastConnectedLegacyReactNativePage = null;
40
+ #isLegacyPageReloading = false;
41
+ #lastGetPagesMessage = "";
42
+ #scriptIdToSourcePathMapping = new Map();
43
+ #deviceEventReporter;
44
+ #pagesPollingIntervalId;
45
+ #createCustomMessageHandler;
46
+ #connectedPageIds = new Set();
47
+ #deviceRelativeBaseUrl;
48
+ #serverRelativeBaseUrl;
49
+ #cdpDebugLogging;
50
+ constructor(deviceOptions) {
51
+ this.#dangerouslyConstruct(deviceOptions);
52
+ }
53
+ #dangerouslyConstruct({
54
+ id,
55
+ name,
56
+ app,
57
+ socket,
58
+ eventReporter,
59
+ createMessageMiddleware,
60
+ serverRelativeBaseUrl,
61
+ deviceRelativeBaseUrl,
62
+ isProfilingBuild,
63
+ }) {
64
+ this.#cdpDebugLogging = new _CdpDebugLogging.default();
65
+ this.#id = id;
66
+ this.#name = name;
67
+ this.#app = app;
68
+ this.#deviceSocket = socket;
69
+ this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
70
+ this.#deviceRelativeBaseUrl = deviceRelativeBaseUrl;
71
+ this.#deviceEventReporter = eventReporter
72
+ ? new _DeviceEventReporter.default(eventReporter, {
73
+ deviceId: id,
74
+ deviceName: name,
75
+ appId: app,
76
+ })
77
+ : null;
78
+ this.#createCustomMessageHandler = createMessageMiddleware;
79
+ if (isProfilingBuild) {
80
+ this.#deviceEventReporter?.logProfilingTargetRegistered();
81
+ }
82
+ this.#deviceSocket.on("message", (message) => {
83
+ try {
84
+ const parsedMessage = JSON.parse(message);
85
+ if (parsedMessage.event === "getPages") {
86
+ if (message !== this.#lastGetPagesMessage) {
87
+ debug("Device getPages ping has changed: %s", message);
88
+ this.#lastGetPagesMessage = message;
89
+ }
90
+ } else {
91
+ this.#cdpDebugLogging.log("DeviceToProxy", message);
92
+ }
93
+ this.#handleMessageFromDevice(parsedMessage);
94
+ } catch (error) {
95
+ debug("%O\nHandling device message: %s", error, message);
96
+ try {
97
+ this.#deviceEventReporter?.logProxyMessageHandlingError(
98
+ "device",
99
+ error,
100
+ message,
101
+ );
102
+ } catch (loggingError) {
103
+ debug(
104
+ "Error logging message handling error to reporter: %O",
105
+ loggingError,
106
+ );
107
+ }
108
+ }
109
+ });
110
+ this.#pagesPollingIntervalId = setInterval(
111
+ () =>
112
+ this.#sendMessageToDevice({
113
+ event: "getPages",
114
+ }),
115
+ PAGES_POLLING_INTERVAL,
116
+ );
117
+ this.#deviceSocket.on("close", () => {
118
+ if (socket === this.#deviceSocket) {
119
+ this.#deviceEventReporter?.logDisconnection("device");
120
+ this.#terminateDebuggerConnection(
121
+ WS_CLOSURE_CODE.NORMAL,
122
+ WS_CLOSE_REASON.CONNECTION_LOST,
123
+ );
124
+ clearInterval(this.#pagesPollingIntervalId);
125
+ }
126
+ });
127
+ }
128
+ #terminateDebuggerConnection(code, reason) {
129
+ const debuggerConnection = this.#debuggerConnection;
130
+ if (debuggerConnection) {
131
+ this.#sendDisconnectEventToDevice(
132
+ this.#mapToDevicePageId(debuggerConnection.pageId),
133
+ );
134
+ debuggerConnection.socket.close(code, reason);
135
+ this.#debuggerConnection = null;
136
+ }
137
+ }
138
+ dangerouslyRecreateDevice(deviceOptions) {
139
+ (0, _invariant.default)(
140
+ deviceOptions.id === this.#id,
141
+ "dangerouslyRecreateDevice() can only be used for the same device ID",
142
+ );
143
+ const oldDebugger = this.#debuggerConnection;
144
+ if (this.#app !== deviceOptions.app || this.#name !== deviceOptions.name) {
145
+ this.#deviceSocket.close(
146
+ WS_CLOSURE_CODE.NORMAL,
147
+ WS_CLOSE_REASON.RECREATING_DEVICE,
148
+ );
149
+ this.#terminateDebuggerConnection(
150
+ WS_CLOSURE_CODE.NORMAL,
151
+ WS_CLOSE_REASON.RECREATING_DEVICE,
152
+ );
153
+ }
154
+ this.#debuggerConnection = null;
155
+ if (oldDebugger) {
156
+ oldDebugger.socket.removeAllListeners();
157
+ this.#deviceSocket.close(
158
+ WS_CLOSURE_CODE.NORMAL,
159
+ WS_CLOSE_REASON.RECREATING_DEVICE,
160
+ );
161
+ this.handleDebuggerConnection(oldDebugger.socket, oldDebugger.pageId, {
162
+ debuggerRelativeBaseUrl: oldDebugger.debuggerRelativeBaseUrl,
163
+ userAgent: oldDebugger.userAgent,
164
+ });
165
+ }
166
+ this.#dangerouslyConstruct(deviceOptions);
167
+ }
168
+ getName() {
169
+ return this.#name;
170
+ }
171
+ getApp() {
172
+ return this.#app;
173
+ }
174
+ getPagesList() {
175
+ if (this.#lastConnectedLegacyReactNativePage) {
176
+ return [...this.#pages.values(), this.#createSyntheticPage()];
177
+ } else {
178
+ return [...this.#pages.values()];
179
+ }
180
+ }
181
+ handleDebuggerConnection(
182
+ socket,
183
+ pageId,
184
+ { debuggerRelativeBaseUrl, userAgent },
185
+ ) {
186
+ const page =
187
+ pageId === REACT_NATIVE_RELOADABLE_PAGE_ID
188
+ ? this.#createSyntheticPage()
189
+ : this.#pages.get(pageId);
190
+ if (!page) {
191
+ debug(
192
+ `Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
193
+ `page ${pageId} of ${this.#name}, but no such page exists`,
194
+ );
195
+ socket.close(
196
+ WS_CLOSURE_CODE.INTERNAL_ERROR,
197
+ WS_CLOSE_REASON.PAGE_NOT_FOUND,
198
+ );
199
+ return;
200
+ }
201
+ this.#deviceEventReporter?.logDisconnection("debugger");
202
+ this.#terminateDebuggerConnection(
203
+ WS_CLOSURE_CODE.NORMAL,
204
+ WS_CLOSE_REASON.NEW_DEBUGGER_OPENED,
205
+ );
206
+ this.#deviceEventReporter?.logConnection("debugger", {
207
+ pageId,
208
+ frontendUserAgent: userAgent,
209
+ });
210
+ const debuggerInfo = {
211
+ socket,
212
+ prependedFilePrefix: false,
213
+ pageId,
214
+ userAgent: userAgent,
215
+ customHandler: null,
216
+ debuggerRelativeBaseUrl,
217
+ };
218
+ this.#debuggerConnection = debuggerInfo;
219
+ debug(
220
+ `Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
221
+ `page ${pageId} of ${this.#name}`,
222
+ );
223
+ if (this.#debuggerConnection && this.#createCustomMessageHandler) {
224
+ this.#debuggerConnection.customHandler = this.#createCustomMessageHandler(
225
+ {
226
+ page,
227
+ debugger: {
228
+ userAgent: debuggerInfo.userAgent,
229
+ sendMessage: (message) => {
230
+ try {
231
+ const payload = JSON.stringify(message);
232
+ this.#cdpDebugLogging.log("ProxyToDebugger", payload);
233
+ socket.send(payload);
234
+ } catch {}
235
+ },
236
+ },
237
+ device: {
238
+ appId: this.#app,
239
+ id: this.#id,
240
+ name: this.#name,
241
+ sendMessage: (message) => {
242
+ try {
243
+ const payload = JSON.stringify({
244
+ event: "wrappedEvent",
245
+ payload: {
246
+ pageId: this.#mapToDevicePageId(pageId),
247
+ wrappedEvent: JSON.stringify(message),
248
+ },
249
+ });
250
+ this.#cdpDebugLogging.log("DebuggerToProxy", payload);
251
+ this.#deviceSocket.send(payload);
252
+ } catch {}
253
+ },
254
+ },
255
+ },
256
+ );
257
+ if (this.#debuggerConnection.customHandler) {
258
+ debug("Created new custom message handler for debugger connection");
259
+ } else {
260
+ debug(
261
+ "Skipping new custom message handler for debugger connection, factory function returned null",
262
+ );
263
+ }
264
+ }
265
+ this.#sendConnectEventToDevice(this.#mapToDevicePageId(pageId));
266
+ socket.on("message", (message) => {
267
+ this.#cdpDebugLogging.log("DebuggerToProxy", message);
268
+ const debuggerRequest = JSON.parse(message);
269
+ this.#deviceEventReporter?.logRequest(debuggerRequest, "debugger", {
270
+ pageId: this.#debuggerConnection?.pageId ?? null,
271
+ frontendUserAgent: userAgent,
272
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(
273
+ this.#debuggerConnection?.pageId,
274
+ ),
275
+ });
276
+ let processedReq = debuggerRequest;
277
+ if (
278
+ this.#debuggerConnection?.customHandler?.handleDebuggerMessage(
279
+ debuggerRequest,
280
+ ) === true
281
+ ) {
282
+ return;
283
+ }
284
+ if (!this.#pageHasCapability(page, "nativeSourceCodeFetching")) {
285
+ processedReq = this.#interceptClientMessageForSourceFetching(
286
+ debuggerRequest,
287
+ debuggerInfo,
288
+ socket,
289
+ );
290
+ }
291
+ if (processedReq) {
292
+ this.#sendMessageToDevice({
293
+ event: "wrappedEvent",
294
+ payload: {
295
+ pageId: this.#mapToDevicePageId(pageId),
296
+ wrappedEvent: JSON.stringify(processedReq),
297
+ },
298
+ });
299
+ }
300
+ });
301
+ socket.on("close", () => {
302
+ debug(`Debugger for page ${pageId} and ${this.#name} disconnected.`);
303
+ this.#deviceEventReporter?.logDisconnection("debugger");
304
+ if (this.#debuggerConnection?.socket === socket) {
305
+ this.#terminateDebuggerConnection();
306
+ }
307
+ });
308
+ const cdpDebugLogging = this.#cdpDebugLogging;
309
+ const sendFunc = socket.send;
310
+ socket.send = function (message) {
311
+ cdpDebugLogging.log("ProxyToDebugger", message);
312
+ return sendFunc.call(socket, message);
313
+ };
314
+ }
315
+ #sendConnectEventToDevice(devicePageId) {
316
+ if (this.#connectedPageIds.has(devicePageId)) {
317
+ return;
318
+ }
319
+ this.#connectedPageIds.add(devicePageId);
320
+ this.#sendMessageToDevice({
321
+ event: "connect",
322
+ payload: {
323
+ pageId: devicePageId,
324
+ },
325
+ });
326
+ }
327
+ #sendDisconnectEventToDevice(devicePageId) {
328
+ if (!this.#connectedPageIds.has(devicePageId)) {
329
+ return;
330
+ }
331
+ this.#connectedPageIds.delete(devicePageId);
332
+ this.#sendMessageToDevice({
333
+ event: "disconnect",
334
+ payload: {
335
+ pageId: devicePageId,
336
+ },
337
+ });
338
+ }
339
+ #pageHasCapability(page, flag) {
340
+ return page.capabilities[flag] === true;
341
+ }
342
+ #createSyntheticPage() {
343
+ return {
344
+ id: REACT_NATIVE_RELOADABLE_PAGE_ID,
345
+ title: "React Native Experimental (Improved Chrome Reloads)",
346
+ vm: "don't use",
347
+ app: this.#app,
348
+ capabilities: {},
349
+ };
350
+ }
351
+ #handleMessageFromDevice(message) {
352
+ if (message.event === "getPages") {
353
+ this.#pages = new Map(
354
+ message.payload.map(({ capabilities, ...page }) => [
355
+ page.id,
356
+ {
357
+ ...page,
358
+ capabilities: capabilities ?? {},
359
+ },
360
+ ]),
361
+ );
362
+ if (message.payload.length !== this.#pages.size) {
363
+ const duplicateIds = new Set();
364
+ const idsSeen = new Set();
365
+ for (const page of message.payload) {
366
+ if (!idsSeen.has(page.id)) {
367
+ idsSeen.add(page.id);
368
+ } else {
369
+ duplicateIds.add(page.id);
370
+ }
371
+ }
372
+ debug(
373
+ `Received duplicate page IDs from device: ${[...duplicateIds].join(", ")}`,
374
+ );
375
+ }
376
+ for (const page of this.#pages.values()) {
377
+ if (this.#pageHasCapability(page, "nativePageReloads")) {
378
+ this.#logFuseboxConsoleNotice();
379
+ continue;
380
+ }
381
+ if (page.title.includes("React")) {
382
+ if (page.id !== this.#lastConnectedLegacyReactNativePage?.id) {
383
+ this.#newLegacyReactNativePage(page);
384
+ break;
385
+ }
386
+ }
387
+ }
388
+ } else if (message.event === "disconnect") {
389
+ const pageId = message.payload.pageId;
390
+ const page = this.#pages.get(pageId);
391
+ if (page != null && this.#pageHasCapability(page, "nativePageReloads")) {
392
+ return;
393
+ }
394
+ const debuggerSocket = this.#debuggerConnection
395
+ ? this.#debuggerConnection.socket
396
+ : null;
397
+ if (debuggerSocket && debuggerSocket.readyState === _ws.default.OPEN) {
398
+ if (
399
+ this.#debuggerConnection != null &&
400
+ this.#debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID
401
+ ) {
402
+ debug(`Legacy page ${pageId} is reloading.`);
403
+ debuggerSocket.send(
404
+ JSON.stringify({
405
+ method: "reload",
406
+ }),
407
+ );
408
+ }
409
+ }
410
+ } else if (message.event === "wrappedEvent") {
411
+ if (this.#debuggerConnection == null) {
412
+ return;
413
+ }
414
+ const debuggerSocket = this.#debuggerConnection.socket;
415
+ if (
416
+ debuggerSocket == null ||
417
+ debuggerSocket.readyState !== _ws.default.OPEN
418
+ ) {
419
+ return;
420
+ }
421
+ const parsedPayload = JSON.parse(message.payload.wrappedEvent);
422
+ const pageId = this.#debuggerConnection?.pageId ?? null;
423
+ if ("id" in parsedPayload) {
424
+ this.#deviceEventReporter?.logResponse(parsedPayload, "device", {
425
+ pageId,
426
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
427
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
428
+ });
429
+ }
430
+ const debuggerConnection = this.#debuggerConnection;
431
+ if (debuggerConnection != null) {
432
+ if (
433
+ debuggerConnection.customHandler?.handleDeviceMessage(
434
+ parsedPayload,
435
+ ) === true
436
+ ) {
437
+ return;
438
+ }
439
+ this.#processMessageFromDeviceLegacy(
440
+ parsedPayload,
441
+ debuggerConnection,
442
+ pageId,
443
+ );
444
+ const messageToSend = JSON.stringify(parsedPayload);
445
+ debuggerSocket.send(messageToSend);
446
+ } else {
447
+ debuggerSocket.send(message.payload.wrappedEvent);
448
+ }
449
+ }
450
+ }
451
+ #sendMessageToDevice(message) {
452
+ try {
453
+ const messageToSend = JSON.stringify(message);
454
+ if (message.event !== "getPages") {
455
+ this.#cdpDebugLogging.log("ProxyToDevice", messageToSend);
456
+ }
457
+ this.#deviceSocket.send(messageToSend);
458
+ } catch (error) {}
459
+ }
460
+ #newLegacyReactNativePage(page) {
461
+ debug(`React Native page updated to ${page.id}`);
462
+ if (
463
+ this.#debuggerConnection == null ||
464
+ this.#debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID
465
+ ) {
466
+ this.#lastConnectedLegacyReactNativePage = page;
467
+ return;
468
+ }
469
+ const oldPageId = this.#lastConnectedLegacyReactNativePage?.id;
470
+ this.#lastConnectedLegacyReactNativePage = page;
471
+ this.#isLegacyPageReloading = true;
472
+ if (oldPageId != null) {
473
+ this.#sendDisconnectEventToDevice(oldPageId);
474
+ }
475
+ this.#sendConnectEventToDevice(page.id);
476
+ const toSend = [
477
+ {
478
+ method: "Runtime.enable",
479
+ id: 1e9,
480
+ },
481
+ {
482
+ method: "Debugger.enable",
483
+ id: 1e9,
484
+ },
485
+ ];
486
+ for (const message of toSend) {
487
+ const pageId = this.#debuggerConnection?.pageId ?? null;
488
+ this.#deviceEventReporter?.logRequest(message, "proxy", {
489
+ pageId,
490
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
491
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
492
+ });
493
+ this.#sendMessageToDevice({
494
+ event: "wrappedEvent",
495
+ payload: {
496
+ pageId: this.#mapToDevicePageId(page.id),
497
+ wrappedEvent: JSON.stringify(message),
498
+ },
499
+ });
500
+ }
501
+ }
502
+ #debuggerRelativeToDeviceRelativeUrl(
503
+ debuggerRelativeUrl,
504
+ { debuggerRelativeBaseUrl },
505
+ ) {
506
+ const deviceRelativeUrl = new URL(debuggerRelativeUrl.href);
507
+ if (debuggerRelativeUrl.origin === debuggerRelativeBaseUrl.origin) {
508
+ deviceRelativeUrl.hostname = this.#deviceRelativeBaseUrl.hostname;
509
+ deviceRelativeUrl.port = this.#deviceRelativeBaseUrl.port;
510
+ deviceRelativeUrl.protocol = this.#deviceRelativeBaseUrl.protocol;
511
+ }
512
+ return deviceRelativeUrl;
513
+ }
514
+ #deviceRelativeUrlToDebuggerRelativeUrl(
515
+ deviceRelativeUrl,
516
+ { debuggerRelativeBaseUrl },
517
+ ) {
518
+ const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
519
+ if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
520
+ debuggerRelativeUrl.hostname = debuggerRelativeBaseUrl.hostname;
521
+ debuggerRelativeUrl.port = debuggerRelativeBaseUrl.port;
522
+ debuggerRelativeUrl.protocol = debuggerRelativeUrl.protocol;
523
+ }
524
+ return debuggerRelativeUrl;
525
+ }
526
+ #deviceRelativeUrlToServerRelativeUrl(deviceRelativeUrl) {
527
+ const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
528
+ if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
529
+ debuggerRelativeUrl.hostname = this.#serverRelativeBaseUrl.hostname;
530
+ debuggerRelativeUrl.port = this.#serverRelativeBaseUrl.port;
531
+ debuggerRelativeUrl.protocol = this.#serverRelativeBaseUrl.protocol;
532
+ }
533
+ return debuggerRelativeUrl;
534
+ }
535
+ #processMessageFromDeviceLegacy(payload, debuggerInfo, pageId) {
536
+ const page = pageId != null ? this.#pages.get(pageId) : null;
537
+ if (
538
+ (!page || !this.#pageHasCapability(page, "nativeSourceCodeFetching")) &&
539
+ payload.method === "Debugger.scriptParsed" &&
540
+ payload.params != null
541
+ ) {
542
+ const params = payload.params;
543
+ if ("sourceMapURL" in params) {
544
+ const sourceMapURL = this.#tryParseHTTPURL(params.sourceMapURL);
545
+ if (sourceMapURL) {
546
+ payload.params.sourceMapURL =
547
+ this.#deviceRelativeUrlToDebuggerRelativeUrl(
548
+ sourceMapURL,
549
+ debuggerInfo,
550
+ ).href;
551
+ }
552
+ }
553
+ if ("url" in params) {
554
+ let serverRelativeUrl = params.url;
555
+ const parsedUrl = this.#tryParseHTTPURL(params.url);
556
+ if (parsedUrl) {
557
+ payload.params.url = this.#deviceRelativeUrlToDebuggerRelativeUrl(
558
+ parsedUrl,
559
+ debuggerInfo,
560
+ ).href;
561
+ serverRelativeUrl =
562
+ this.#deviceRelativeUrlToServerRelativeUrl(parsedUrl).href;
563
+ }
564
+ if (payload.params.url.match(/^[0-9a-z]+$/)) {
565
+ payload.params.url = FILE_PREFIX + payload.params.url;
566
+ debuggerInfo.prependedFilePrefix = true;
567
+ }
568
+ if ("scriptId" in params && params.scriptId != null) {
569
+ this.#scriptIdToSourcePathMapping.set(
570
+ params.scriptId,
571
+ serverRelativeUrl,
572
+ );
573
+ }
574
+ }
575
+ }
576
+ if (
577
+ payload.method === "Runtime.executionContextCreated" &&
578
+ this.#isLegacyPageReloading
579
+ ) {
580
+ debuggerInfo.socket.send(
581
+ JSON.stringify({
582
+ method: "Runtime.executionContextsCleared",
583
+ }),
584
+ );
585
+ const resumeMessage = {
586
+ method: "Debugger.resume",
587
+ id: 0,
588
+ };
589
+ this.#deviceEventReporter?.logRequest(resumeMessage, "proxy", {
590
+ pageId: this.#debuggerConnection?.pageId ?? null,
591
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
592
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(
593
+ this.#debuggerConnection?.pageId,
594
+ ),
595
+ });
596
+ this.#sendMessageToDevice({
597
+ event: "wrappedEvent",
598
+ payload: {
599
+ pageId: this.#mapToDevicePageId(debuggerInfo.pageId),
600
+ wrappedEvent: JSON.stringify(resumeMessage),
601
+ },
602
+ });
603
+ this.#isLegacyPageReloading = false;
604
+ }
605
+ if (payload.method === "Runtime.consoleAPICalled") {
606
+ const callFrames = payload.params?.stackTrace?.callFrames ?? [];
607
+ for (const callFrame of callFrames) {
608
+ if (callFrame.url) {
609
+ const parsedUrl = this.#tryParseHTTPURL(callFrame.url);
610
+ if (parsedUrl) {
611
+ callFrame.url = this.#deviceRelativeUrlToDebuggerRelativeUrl(
612
+ parsedUrl,
613
+ debuggerInfo,
614
+ ).href;
615
+ }
616
+ }
617
+ }
618
+ }
619
+ }
620
+ #interceptClientMessageForSourceFetching(req, debuggerInfo, socket) {
621
+ switch (req.method) {
622
+ case "Debugger.setBreakpointByUrl":
623
+ return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo);
624
+ case "Debugger.getScriptSource":
625
+ void this.#processDebuggerGetScriptSource(req, socket);
626
+ return null;
627
+ case "Network.loadNetworkResource":
628
+ const response = {
629
+ id: req.id,
630
+ result: {
631
+ error: {
632
+ code: -32601,
633
+ message:
634
+ "[inspector-proxy]: Page lacks nativeSourceCodeFetching capability.",
635
+ },
636
+ },
637
+ };
638
+ socket.send(JSON.stringify(response));
639
+ const pageId = this.#debuggerConnection?.pageId ?? null;
640
+ this.#deviceEventReporter?.logResponse(response, "proxy", {
641
+ pageId,
642
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
643
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
644
+ });
645
+ return null;
646
+ default:
647
+ return req;
648
+ }
649
+ }
650
+ #processDebuggerSetBreakpointByUrl(req, debuggerInfo) {
651
+ const { debuggerRelativeBaseUrl, prependedFilePrefix } = debuggerInfo;
652
+ const processedReq = {
653
+ ...req,
654
+ params: {
655
+ ...req.params,
656
+ },
657
+ };
658
+ if (processedReq.params.url != null) {
659
+ const originalUrlParam = processedReq.params.url;
660
+ const httpUrl = this.#tryParseHTTPURL(originalUrlParam);
661
+ if (httpUrl) {
662
+ processedReq.params.url = this.#debuggerRelativeToDeviceRelativeUrl(
663
+ httpUrl,
664
+ debuggerInfo,
665
+ ).href;
666
+ } else if (
667
+ originalUrlParam.startsWith(FILE_PREFIX) &&
668
+ prependedFilePrefix
669
+ ) {
670
+ processedReq.params.url = originalUrlParam.slice(FILE_PREFIX.length);
671
+ }
672
+ }
673
+ if (
674
+ new Set(["10.0.2.2", "10.0.3.2"]).has(
675
+ this.#deviceRelativeBaseUrl.hostname,
676
+ ) &&
677
+ debuggerRelativeBaseUrl.hostname === "localhost" &&
678
+ processedReq.params.urlRegex != null
679
+ ) {
680
+ processedReq.params.urlRegex = processedReq.params.urlRegex.replaceAll(
681
+ "localhost",
682
+ this.#deviceRelativeBaseUrl.hostname.replaceAll(".", "\\."),
683
+ );
684
+ }
685
+ return processedReq;
686
+ }
687
+ async #processDebuggerGetScriptSource(req, socket) {
688
+ const sendSuccessResponse = (scriptSource) => {
689
+ const response = {
690
+ id: req.id,
691
+ result: {
692
+ scriptSource,
693
+ },
694
+ };
695
+ socket.send(JSON.stringify(response));
696
+ const pageId = this.#debuggerConnection?.pageId ?? null;
697
+ this.#deviceEventReporter?.logResponse(response, "proxy", {
698
+ pageId,
699
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
700
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
701
+ });
702
+ };
703
+ const sendErrorResponse = (error) => {
704
+ const response = {
705
+ id: req.id,
706
+ result: {
707
+ error: {
708
+ message: error,
709
+ },
710
+ },
711
+ };
712
+ socket.send(JSON.stringify(response));
713
+ this.#sendErrorToDebugger(error);
714
+ const pageId = this.#debuggerConnection?.pageId ?? null;
715
+ this.#deviceEventReporter?.logResponse(response, "proxy", {
716
+ pageId,
717
+ frontendUserAgent: this.#debuggerConnection?.userAgent ?? null,
718
+ prefersFuseboxFrontend: this.#isPageFuseboxFrontend(pageId),
719
+ });
720
+ };
721
+ const pathToSource = this.#scriptIdToSourcePathMapping.get(
722
+ req.params.scriptId,
723
+ );
724
+ try {
725
+ const httpURL =
726
+ pathToSource == null ? null : this.#tryParseHTTPURL(pathToSource);
727
+ if (!httpURL) {
728
+ throw new Error(
729
+ `Can't parse requested URL ${pathToSource === undefined ? "undefined" : JSON.stringify(pathToSource)}`,
730
+ );
731
+ }
732
+ const text = await this.#fetchText(httpURL);
733
+ sendSuccessResponse(text);
734
+ } catch (err) {
735
+ sendErrorResponse(
736
+ `Failed to fetch source url ${pathToSource === undefined ? "undefined" : JSON.stringify(pathToSource)} for scriptId ${req.params.scriptId}: ${err.message}`,
737
+ );
738
+ }
739
+ }
740
+ #mapToDevicePageId(pageId) {
741
+ if (
742
+ pageId === REACT_NATIVE_RELOADABLE_PAGE_ID &&
743
+ this.#lastConnectedLegacyReactNativePage != null
744
+ ) {
745
+ return this.#lastConnectedLegacyReactNativePage.id;
746
+ } else {
747
+ return pageId;
748
+ }
749
+ }
750
+ #tryParseHTTPURL(url) {
751
+ let parsedURL;
752
+ try {
753
+ parsedURL = new URL(url);
754
+ } catch {}
755
+ const protocol = parsedURL?.protocol;
756
+ if (protocol !== "http:" && protocol !== "https:") {
757
+ parsedURL = undefined;
758
+ }
759
+ return parsedURL;
760
+ }
761
+ async #fetchText(url) {
762
+ const response = await fetch(url);
763
+ if (!response.ok) {
764
+ throw new Error("HTTP " + response.status + " " + response.statusText);
765
+ }
766
+ const text = await response.text();
767
+ if (text.length > 350000000) {
768
+ throw new Error("file too large to fetch via HTTP");
769
+ }
770
+ return text;
771
+ }
772
+ #sendErrorToDebugger(message) {
773
+ const debuggerSocket = this.#debuggerConnection?.socket;
774
+ if (debuggerSocket && debuggerSocket.readyState === _ws.default.OPEN) {
775
+ debuggerSocket.send(
776
+ JSON.stringify({
777
+ method: "Runtime.consoleAPICalled",
778
+ params: {
779
+ args: [
780
+ {
781
+ type: "string",
782
+ value: message,
783
+ },
784
+ ],
785
+ executionContextId: 0,
786
+ type: "error",
787
+ },
788
+ }),
789
+ );
790
+ }
791
+ }
792
+ #isPageFuseboxFrontend(pageId) {
793
+ const page = pageId == null ? null : this.#pages.get(pageId);
794
+ if (page == null) {
795
+ return null;
796
+ }
797
+ return this.#pageHasCapability(page, "prefersFuseboxFrontend");
798
+ }
799
+ dangerouslyGetSocket() {
800
+ return this.#deviceSocket;
801
+ }
802
+ #logFuseboxConsoleNotice() {
803
+ if (fuseboxConsoleNoticeLogged) {
804
+ return;
805
+ }
806
+ this.#deviceEventReporter?.logFuseboxConsoleNotice();
807
+ fuseboxConsoleNoticeLogged = true;
808
+ }
809
+ }
810
+ exports.default = Device;