@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.
- package/dist/modules/dev/dev-menu/keyboard-handler.d.ts +1 -0
- package/dist/modules/dev/dev-menu/keyboard-handler.js +9 -1
- package/dist/modules/dev/dev-server/cdp/index.d.ts +2 -0
- package/dist/modules/dev/dev-server/cdp/index.js +18 -0
- package/dist/modules/dev/dev-server/cdp/types.d.ts +107 -0
- package/dist/modules/dev/dev-server/cdp/types.js +2 -0
- package/dist/modules/dev/dev-server/dev-server.d.ts +2 -0
- package/dist/modules/dev/dev-server/dev-server.js +48 -25
- package/dist/modules/dev/dev-server/inspector/device.d.ts +46 -0
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.d.ts +37 -0
- package/dist/modules/dev/dev-server/inspector/device.event-reporter.js +165 -0
- package/dist/modules/dev/dev-server/inspector/device.js +577 -0
- package/dist/modules/dev/dev-server/inspector/inspector.d.ts +27 -0
- package/dist/modules/dev/dev-server/inspector/inspector.js +205 -0
- package/dist/modules/dev/dev-server/inspector/types.d.ts +156 -0
- package/dist/modules/dev/dev-server/inspector/types.js +2 -0
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.d.ts +14 -0
- package/dist/modules/dev/dev-server/inspector/wss/servers/debugger-connection.server.js +61 -0
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.d.ts +19 -0
- package/dist/modules/dev/dev-server/inspector/wss/servers/device-connection.server.js +64 -0
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +1 -2
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.d.ts +3 -0
- package/dist/modules/dev/dev-server/sybmolicate/sybmolicate.plugin.js +7 -1
- package/dist/modules/dev/terminal/terminal.reporter.d.ts +3 -1
- package/dist/modules/dev/terminal/terminal.reporter.js +3 -0
- package/package.json +4 -4
|
@@ -0,0 +1,205 @@
|
|
|
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.Inspector = void 0;
|
|
7
|
+
const ws_1 = require("ws");
|
|
8
|
+
const node_url_1 = require("node:url");
|
|
9
|
+
const node_url_2 = __importDefault(require("node:url"));
|
|
10
|
+
const device_1 = require("./device");
|
|
11
|
+
const WS_DEVICE_PATH = "/inspector/device";
|
|
12
|
+
const WS_DEBUGGER_PATH = "/inspector/debug";
|
|
13
|
+
const JSON_VERSION_PATH = "/json/version";
|
|
14
|
+
const JSON_LIST_PATH = "/json";
|
|
15
|
+
const JSON_LIST_PATH_2 = "/json/list";
|
|
16
|
+
const HEARTBEAT_INTERVAL = 10000;
|
|
17
|
+
const MAX_PONG_TIMEOUT = 5000;
|
|
18
|
+
const INTERNAL_ERROR_CODE = 1011;
|
|
19
|
+
class Inspector {
|
|
20
|
+
devices = new Map();
|
|
21
|
+
deviceCounter = 0;
|
|
22
|
+
projectRoot;
|
|
23
|
+
serverBaseUrl;
|
|
24
|
+
eventReporter;
|
|
25
|
+
cdpAdapter;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.projectRoot = options.projectRoot;
|
|
28
|
+
this.serverBaseUrl = options.serverBaseUrl;
|
|
29
|
+
this.eventReporter = options.eventReporter;
|
|
30
|
+
this.cdpAdapter = options.cdpAdapter;
|
|
31
|
+
this.handleHttpRequest = this.handleHttpRequest.bind(this);
|
|
32
|
+
this.sendJsonResponse = this.sendJsonResponse.bind(this);
|
|
33
|
+
}
|
|
34
|
+
getPageDescriptions() {
|
|
35
|
+
const descriptions = [];
|
|
36
|
+
for (const [deviceId, device] of this.devices.entries()) {
|
|
37
|
+
const devicePages = device
|
|
38
|
+
.getPagesList()
|
|
39
|
+
.map((page) => this.createPageDescription(deviceId, device, page));
|
|
40
|
+
descriptions.push(...devicePages);
|
|
41
|
+
}
|
|
42
|
+
return descriptions;
|
|
43
|
+
}
|
|
44
|
+
handleHttpRequest = (req, res, next) => {
|
|
45
|
+
const pathname = new node_url_1.URL(req.url || "", "http://localhost").pathname;
|
|
46
|
+
if (pathname === JSON_LIST_PATH || pathname === JSON_LIST_PATH_2) {
|
|
47
|
+
this.sendJsonResponse(res, this.getPageDescriptions());
|
|
48
|
+
}
|
|
49
|
+
else if (pathname === JSON_VERSION_PATH) {
|
|
50
|
+
this.sendJsonResponse(res, {
|
|
51
|
+
Browser: "Mobile JavaScript",
|
|
52
|
+
"Protocol-Version": "1.1",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
next();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
createWebSocketServers() {
|
|
60
|
+
return {
|
|
61
|
+
[WS_DEVICE_PATH]: this.createDeviceWebSocketServer(),
|
|
62
|
+
[WS_DEBUGGER_PATH]: this.createDebuggerWebSocketServer(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
createPageDescription(deviceId, device, page) {
|
|
66
|
+
const { host, protocol } = new node_url_1.URL(this.serverBaseUrl);
|
|
67
|
+
const wsProtocol = protocol === "https:" ? "wss" : "ws";
|
|
68
|
+
const wsPath = `${host}${WS_DEBUGGER_PATH}?device=${deviceId}&page=${page.id}`;
|
|
69
|
+
return {
|
|
70
|
+
id: `${deviceId}-${page.id}`,
|
|
71
|
+
title: page.title,
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
description: page.description || page.app,
|
|
74
|
+
type: "node",
|
|
75
|
+
webSocketDebuggerUrl: `${wsProtocol}://${wsPath}`,
|
|
76
|
+
devtoolsFrontendUrl: `devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&${wsProtocol}=${encodeURIComponent(wsPath)}`,
|
|
77
|
+
deviceName: device.getName(),
|
|
78
|
+
appId: page.app,
|
|
79
|
+
vm: page.vm,
|
|
80
|
+
reactNative: {
|
|
81
|
+
logicalDeviceId: deviceId,
|
|
82
|
+
capabilities: page.capabilities,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
createDeviceWebSocketServer() {
|
|
87
|
+
const wss = new ws_1.WebSocketServer({
|
|
88
|
+
noServer: true,
|
|
89
|
+
perMessageDeflate: true,
|
|
90
|
+
maxPayload: 0,
|
|
91
|
+
});
|
|
92
|
+
wss.on("connection", (socket, req) => {
|
|
93
|
+
try {
|
|
94
|
+
const fallbackDeviceId = String(this.deviceCounter++);
|
|
95
|
+
const query = node_url_2.default.parse(req.url || "", true).query || {};
|
|
96
|
+
const deviceId = query.device || fallbackDeviceId;
|
|
97
|
+
const deviceName = query.name || "Unknown";
|
|
98
|
+
const appName = query.app || "Unknown";
|
|
99
|
+
const actualDeviceId = Array.isArray(deviceId) ? deviceId[0] : deviceId;
|
|
100
|
+
const actualDeviceName = Array.isArray(deviceName)
|
|
101
|
+
? deviceName[0]
|
|
102
|
+
: deviceName;
|
|
103
|
+
const actualAppName = Array.isArray(appName) ? appName[0] : appName;
|
|
104
|
+
const oldDevice = this.devices.get(actualDeviceId);
|
|
105
|
+
let newDevice;
|
|
106
|
+
if (oldDevice) {
|
|
107
|
+
oldDevice.dangerouslyRecreateDevice(actualDeviceId, actualDeviceName, actualAppName, socket, this.projectRoot, this.eventReporter);
|
|
108
|
+
newDevice = oldDevice;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
newDevice = new device_1.Device(actualDeviceId, actualDeviceName, actualAppName, socket, this.projectRoot, this.eventReporter);
|
|
112
|
+
}
|
|
113
|
+
this.devices.set(actualDeviceId, newDevice);
|
|
114
|
+
socket.on("close", () => {
|
|
115
|
+
if (this.devices.get(actualDeviceId)?.dangerouslyGetSocket() === socket) {
|
|
116
|
+
this.devices.delete(actualDeviceId);
|
|
117
|
+
}
|
|
118
|
+
// debug(`Device ${deviceName} disconnected.`);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
console.error("error", e);
|
|
123
|
+
socket.close(INTERNAL_ERROR_CODE, e?.toString() ?? "Unknown error");
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return wss;
|
|
127
|
+
}
|
|
128
|
+
createDebuggerWebSocketServer() {
|
|
129
|
+
const wss = new ws_1.WebSocketServer({
|
|
130
|
+
noServer: true,
|
|
131
|
+
maxPayload: 0,
|
|
132
|
+
});
|
|
133
|
+
wss.on("connection", (ws, req) => {
|
|
134
|
+
try {
|
|
135
|
+
const query = new node_url_1.URL(req.url || "", "http://localhost").searchParams;
|
|
136
|
+
const deviceId = query.get("device");
|
|
137
|
+
const pageId = query.get("page");
|
|
138
|
+
if (!deviceId || !pageId) {
|
|
139
|
+
throw new Error("Missing device or page ID");
|
|
140
|
+
}
|
|
141
|
+
const device = this.devices.get(deviceId);
|
|
142
|
+
if (!device) {
|
|
143
|
+
throw new Error(`Unknown device: ${deviceId}`);
|
|
144
|
+
}
|
|
145
|
+
this.setupHeartbeat(ws);
|
|
146
|
+
device.handleDebuggerConnection(ws, pageId, {
|
|
147
|
+
userAgent: req.headers["user-agent"] || null,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error(err);
|
|
152
|
+
ws.close(INTERNAL_ERROR_CODE, err instanceof Error ? err.message : "Unknown error");
|
|
153
|
+
this.eventReporter?.logEvent({
|
|
154
|
+
type: "connect_debugger_frontend",
|
|
155
|
+
status: "error",
|
|
156
|
+
error: err,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
return wss;
|
|
161
|
+
}
|
|
162
|
+
setupHeartbeat(ws) {
|
|
163
|
+
let pendingPong = false;
|
|
164
|
+
let terminateTimeout = null;
|
|
165
|
+
const heartbeat = setInterval(() => {
|
|
166
|
+
if (ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
pendingPong = true;
|
|
170
|
+
ws.ping(() => {
|
|
171
|
+
if (!pendingPong)
|
|
172
|
+
return;
|
|
173
|
+
terminateTimeout = setTimeout(() => {
|
|
174
|
+
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
175
|
+
ws.terminate();
|
|
176
|
+
}
|
|
177
|
+
}, MAX_PONG_TIMEOUT);
|
|
178
|
+
});
|
|
179
|
+
}, HEARTBEAT_INTERVAL);
|
|
180
|
+
const resetHeartbeat = () => {
|
|
181
|
+
pendingPong = false;
|
|
182
|
+
if (terminateTimeout) {
|
|
183
|
+
clearTimeout(terminateTimeout);
|
|
184
|
+
terminateTimeout = null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
ws.on("pong", resetHeartbeat);
|
|
188
|
+
ws.on("message", resetHeartbeat);
|
|
189
|
+
ws.on("close", () => {
|
|
190
|
+
clearInterval(heartbeat);
|
|
191
|
+
resetHeartbeat();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
sendJsonResponse = (res, data) => {
|
|
195
|
+
const json = JSON.stringify(data, null, 2);
|
|
196
|
+
res.writeHead(200, {
|
|
197
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
198
|
+
"Cache-Control": "no-cache",
|
|
199
|
+
"Content-Length": Buffer.byteLength(json),
|
|
200
|
+
Connection: "close",
|
|
201
|
+
});
|
|
202
|
+
res.end(json);
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
exports.Inspector = Inspector;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type WS from "ws";
|
|
2
|
+
export type JSONSerializable = boolean | number | string | null | ReadonlyArray<JSONSerializable> | {
|
|
3
|
+
[key: string]: JSONSerializable;
|
|
4
|
+
};
|
|
5
|
+
export interface PageFromDevice {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
vm: string;
|
|
9
|
+
app: string;
|
|
10
|
+
capabilities: Record<string, boolean>;
|
|
11
|
+
}
|
|
12
|
+
export type Page = Omit<PageFromDevice, "capabilities"> & {
|
|
13
|
+
capabilities: NonNullable<PageFromDevice["capabilities"]>;
|
|
14
|
+
};
|
|
15
|
+
export type WrappedEvent = {
|
|
16
|
+
event: "wrappedEvent";
|
|
17
|
+
payload: {
|
|
18
|
+
pageId: string;
|
|
19
|
+
wrappedEvent: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export type ConnectRequest = {
|
|
23
|
+
event: "connect";
|
|
24
|
+
payload: {
|
|
25
|
+
pageId: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export type DisconnectRequest = {
|
|
29
|
+
event: "disconnect";
|
|
30
|
+
payload: {
|
|
31
|
+
pageId: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export type GetPagesRequest = {
|
|
35
|
+
event: "getPages";
|
|
36
|
+
};
|
|
37
|
+
export type GetPagesResponse = {
|
|
38
|
+
event: "getPages";
|
|
39
|
+
payload: ReadonlyArray<PageFromDevice>;
|
|
40
|
+
};
|
|
41
|
+
export type MessageFromDevice = GetPagesResponse | WrappedEvent | DisconnectRequest;
|
|
42
|
+
export type MessageToDevice = GetPagesRequest | WrappedEvent | ConnectRequest | DisconnectRequest;
|
|
43
|
+
export type PageDescription = {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
appId: string;
|
|
47
|
+
description: string;
|
|
48
|
+
type: string;
|
|
49
|
+
devtoolsFrontendUrl: string;
|
|
50
|
+
webSocketDebuggerUrl: string;
|
|
51
|
+
/** @deprecated Prefer `title` */
|
|
52
|
+
deviceName: string;
|
|
53
|
+
/** @deprecated This is sent from legacy targets only */
|
|
54
|
+
vm?: string;
|
|
55
|
+
reactNative: {
|
|
56
|
+
logicalDeviceId: string;
|
|
57
|
+
capabilities: Page["capabilities"];
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export interface CDPMessage {
|
|
61
|
+
id?: number;
|
|
62
|
+
method?: string;
|
|
63
|
+
params?: any;
|
|
64
|
+
result?: any;
|
|
65
|
+
}
|
|
66
|
+
export interface DebuggerConnection {
|
|
67
|
+
socket: WS;
|
|
68
|
+
originalSourceURLAddress?: string;
|
|
69
|
+
prependedFilePrefix: boolean;
|
|
70
|
+
pageId: string;
|
|
71
|
+
userAgent: string | null;
|
|
72
|
+
customHandler: any | null;
|
|
73
|
+
}
|
|
74
|
+
type SuccessResult<Props extends Record<string, any> = {}> = {
|
|
75
|
+
status: "success";
|
|
76
|
+
} & Props;
|
|
77
|
+
type ErrorResult<ErrorT = unknown> = {
|
|
78
|
+
status: "error";
|
|
79
|
+
error: ErrorT;
|
|
80
|
+
prefersFuseboxFrontend?: boolean | null;
|
|
81
|
+
};
|
|
82
|
+
type CodedErrorResult<ErrorCode extends string> = {
|
|
83
|
+
status: "coded_error";
|
|
84
|
+
errorCode: ErrorCode;
|
|
85
|
+
errorDetails?: string;
|
|
86
|
+
};
|
|
87
|
+
type DebuggerSessionIDs = {
|
|
88
|
+
appId: string;
|
|
89
|
+
deviceName: string;
|
|
90
|
+
deviceId: string;
|
|
91
|
+
pageId: string | null;
|
|
92
|
+
};
|
|
93
|
+
export type ReportableEvent = ({
|
|
94
|
+
type: "launch_debugger_frontend";
|
|
95
|
+
launchType: "launch" | "redirect";
|
|
96
|
+
} & (SuccessResult<{
|
|
97
|
+
appId: string | null;
|
|
98
|
+
deviceId: string | null;
|
|
99
|
+
resolvedTargetDescription: string;
|
|
100
|
+
resolvedTargetAppId: string;
|
|
101
|
+
prefersFuseboxFrontend: boolean;
|
|
102
|
+
}> | ErrorResult | CodedErrorResult<"NO_APPS_FOUND">)) | ({
|
|
103
|
+
type: "connect_debugger_frontend";
|
|
104
|
+
} & (SuccessResult<{
|
|
105
|
+
frontendUserAgent: string | null;
|
|
106
|
+
} & DebuggerSessionIDs> | ErrorResult)) | ({
|
|
107
|
+
type: "debugger_command";
|
|
108
|
+
protocol: "CDP";
|
|
109
|
+
method: string | null;
|
|
110
|
+
requestOrigin: "proxy" | "debugger" | null;
|
|
111
|
+
responseOrigin: "proxy" | "device";
|
|
112
|
+
timeSinceStart: number | null;
|
|
113
|
+
frontendUserAgent: string | null;
|
|
114
|
+
prefersFuseboxFrontend: boolean | null;
|
|
115
|
+
} & DebuggerSessionIDs & (SuccessResult | CodedErrorResult<"TIMED_OUT" | "DEVICE_DISCONNECTED" | "DEBUGGER_DISCONNECTED" | "UNMATCHED_REQUEST_ID" | "PROTOCOL_ERROR">)) | ({
|
|
116
|
+
type: "proxy_error";
|
|
117
|
+
status: "error";
|
|
118
|
+
messageOrigin: "debugger" | "device";
|
|
119
|
+
message: string;
|
|
120
|
+
error: string;
|
|
121
|
+
errorStack: string;
|
|
122
|
+
} & DebuggerSessionIDs);
|
|
123
|
+
export interface EventReporter {
|
|
124
|
+
logEvent(event: ReportableEvent): void;
|
|
125
|
+
}
|
|
126
|
+
export type ExposedDevice = {
|
|
127
|
+
appId: string;
|
|
128
|
+
id: string;
|
|
129
|
+
name: string;
|
|
130
|
+
sendMessage: (message: JSONSerializable) => void;
|
|
131
|
+
};
|
|
132
|
+
export type ExposedDebugger = {
|
|
133
|
+
userAgent: string | null;
|
|
134
|
+
sendMessage: (message: JSONSerializable) => void;
|
|
135
|
+
};
|
|
136
|
+
export type CustomMessageHandlerConnection = {
|
|
137
|
+
page: Page;
|
|
138
|
+
device: ExposedDevice;
|
|
139
|
+
debugger: ExposedDebugger;
|
|
140
|
+
};
|
|
141
|
+
export type CreateCustomMessageHandlerFn = (connection: CustomMessageHandlerConnection) => CustomMessageHandler;
|
|
142
|
+
export interface CustomMessageHandler {
|
|
143
|
+
/**
|
|
144
|
+
* Handle a CDP message coming from the device.
|
|
145
|
+
* This is invoked before the message is sent to the debugger.
|
|
146
|
+
* When returning true, the message is considered handled and will not be sent to the debugger.
|
|
147
|
+
*/
|
|
148
|
+
handleDeviceMessage(message: JSONSerializable): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Handle a CDP message coming from the debugger.
|
|
151
|
+
* This is invoked before the message is sent to the device.
|
|
152
|
+
* When returning true, the message is considered handled and will not be sent to the device.
|
|
153
|
+
*/
|
|
154
|
+
handleDebuggerMessage(message: JSONSerializable): boolean;
|
|
155
|
+
}
|
|
156
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import WS from "ws";
|
|
2
|
+
import type { EventReporter } from "../../types";
|
|
3
|
+
import type { Device } from "../../device";
|
|
4
|
+
interface DebuggerConnectionServerConfig {
|
|
5
|
+
devices: Map<string, Device>;
|
|
6
|
+
eventReporter: EventReporter | null;
|
|
7
|
+
startHeartbeat: (socket: WS, intervalMs: number) => void;
|
|
8
|
+
}
|
|
9
|
+
export default class DebuggerConnectionServer {
|
|
10
|
+
#private;
|
|
11
|
+
constructor({ devices, eventReporter, startHeartbeat, }: DebuggerConnectionServerConfig);
|
|
12
|
+
createServer(): WS.Server;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
const node_url_1 = __importDefault(require("node:url"));
|
|
7
|
+
const ws_1 = __importDefault(require("ws"));
|
|
8
|
+
const debug = require("debug")("Metro:InspectorProxy");
|
|
9
|
+
const INTERNAL_ERROR_CODE = 1011;
|
|
10
|
+
const DEBUGGER_HEARTBEAT_INTERVAL_MS = 10000;
|
|
11
|
+
const MAX_PONG_LATENCY_MS = 5000;
|
|
12
|
+
class DebuggerConnectionServer {
|
|
13
|
+
#devices;
|
|
14
|
+
#eventReporter;
|
|
15
|
+
#startHeartbeat;
|
|
16
|
+
constructor({ devices, eventReporter, startHeartbeat, }) {
|
|
17
|
+
this.#devices = devices;
|
|
18
|
+
this.#eventReporter = eventReporter;
|
|
19
|
+
this.#startHeartbeat = startHeartbeat;
|
|
20
|
+
}
|
|
21
|
+
createServer() {
|
|
22
|
+
const wss = new ws_1.default.Server({
|
|
23
|
+
noServer: true,
|
|
24
|
+
perMessageDeflate: false,
|
|
25
|
+
// Don't crash on exceptionally large messages - assume the debugger is
|
|
26
|
+
// well-behaved and the device is prepared to handle large messages.
|
|
27
|
+
maxPayload: 0,
|
|
28
|
+
});
|
|
29
|
+
wss.on("connection", async (socket, req) => {
|
|
30
|
+
try {
|
|
31
|
+
const query = node_url_1.default.parse(req.url || "", true).query || {};
|
|
32
|
+
const deviceId = query.device;
|
|
33
|
+
const pageId = query.page;
|
|
34
|
+
if (deviceId == null || pageId == null) {
|
|
35
|
+
throw new Error("Incorrect URL - must provide device and page IDs");
|
|
36
|
+
}
|
|
37
|
+
const device = this.#devices.get(deviceId);
|
|
38
|
+
if (device == null) {
|
|
39
|
+
throw new Error(`Unknown device with ID ${deviceId}`);
|
|
40
|
+
}
|
|
41
|
+
this.#startHeartbeat(socket, DEBUGGER_HEARTBEAT_INTERVAL_MS);
|
|
42
|
+
device.handleDebuggerConnection(socket, pageId, {
|
|
43
|
+
userAgent: Array.isArray(req.headers["user-agent"])
|
|
44
|
+
? req.headers["user-agent"][0]
|
|
45
|
+
: req.headers["user-agent"] || query.userAgent || null,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
console.error(e);
|
|
50
|
+
socket.close(INTERNAL_ERROR_CODE, e?.toString() ?? "Unknown error");
|
|
51
|
+
this.#eventReporter?.logEvent({
|
|
52
|
+
type: "connect_debugger_frontend",
|
|
53
|
+
status: "error",
|
|
54
|
+
error: e,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return wss;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.default = DebuggerConnectionServer;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import WS from "ws";
|
|
2
|
+
import { Device } from "../../device";
|
|
3
|
+
import type { EventReporter, CreateCustomMessageHandlerFn } from "../../types";
|
|
4
|
+
interface DeviceCounter {
|
|
5
|
+
value: number;
|
|
6
|
+
}
|
|
7
|
+
interface DeviceConnectionServerConfig {
|
|
8
|
+
devices: Map<string, Device>;
|
|
9
|
+
deviceCounter: DeviceCounter;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
eventReporter?: EventReporter;
|
|
12
|
+
customMessageHandler: CreateCustomMessageHandlerFn | null;
|
|
13
|
+
}
|
|
14
|
+
export default class DeviceConnectionServer {
|
|
15
|
+
#private;
|
|
16
|
+
constructor({ devices, deviceCounter, projectRoot, eventReporter, customMessageHandler, }: DeviceConnectionServerConfig);
|
|
17
|
+
createServer(): WS.Server;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
const ws_1 = __importDefault(require("ws"));
|
|
7
|
+
const node_url_1 = __importDefault(require("node:url"));
|
|
8
|
+
const device_1 = require("../../device");
|
|
9
|
+
const debug = require("debug")("Metro:InspectorProxy");
|
|
10
|
+
const INTERNAL_ERROR_CODE = 1011;
|
|
11
|
+
class DeviceConnectionServer {
|
|
12
|
+
#devices;
|
|
13
|
+
#deviceCounter;
|
|
14
|
+
#projectRoot;
|
|
15
|
+
#eventReporter;
|
|
16
|
+
#customMessageHandler;
|
|
17
|
+
constructor({ devices, deviceCounter, projectRoot, eventReporter, customMessageHandler, }) {
|
|
18
|
+
this.#devices = devices;
|
|
19
|
+
this.#deviceCounter = deviceCounter;
|
|
20
|
+
this.#projectRoot = projectRoot;
|
|
21
|
+
this.#eventReporter = eventReporter;
|
|
22
|
+
this.#customMessageHandler = customMessageHandler;
|
|
23
|
+
}
|
|
24
|
+
createServer() {
|
|
25
|
+
const wss = new ws_1.default.Server({
|
|
26
|
+
noServer: true,
|
|
27
|
+
perMessageDeflate: true,
|
|
28
|
+
maxPayload: 0,
|
|
29
|
+
});
|
|
30
|
+
wss.on("connection", async (socket, req) => {
|
|
31
|
+
try {
|
|
32
|
+
const fallbackDeviceId = String(this.#deviceCounter.value++);
|
|
33
|
+
const query = node_url_1.default.parse(req.url || "", true).query || {};
|
|
34
|
+
const deviceId = query.device || fallbackDeviceId;
|
|
35
|
+
const deviceName = query.name || "Unknown";
|
|
36
|
+
const appName = query.app || "Unknown";
|
|
37
|
+
const oldDevice = this.#devices.get(deviceId);
|
|
38
|
+
let newDevice;
|
|
39
|
+
if (oldDevice) {
|
|
40
|
+
oldDevice.dangerouslyRecreateDevice(deviceId, deviceName, appName, socket, this.#projectRoot, this.#eventReporter);
|
|
41
|
+
newDevice = oldDevice;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
newDevice = new device_1.Device(deviceId, deviceName, appName, socket, this.#projectRoot, this.#eventReporter);
|
|
45
|
+
}
|
|
46
|
+
this.#devices.set(deviceId, newDevice);
|
|
47
|
+
debug(`Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}`);
|
|
48
|
+
socket.on("close", () => {
|
|
49
|
+
const device = this.#devices.get(deviceId);
|
|
50
|
+
if (device?.dangerouslyGetSocket() === socket) {
|
|
51
|
+
this.#devices.delete(deviceId);
|
|
52
|
+
}
|
|
53
|
+
debug(`Device ${deviceName} disconnected.`);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.error("error", e);
|
|
58
|
+
socket.close(INTERNAL_ERROR_CODE, e?.toString() ?? "Unknown error");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return wss;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.default = DeviceConnectionServer;
|
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.faviconPlugin = void 0;
|
|
7
|
-
const fastify_favicon_1 = __importDefault(require("fastify-favicon"));
|
|
8
7
|
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
9
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
9
|
const node_url_1 = require("node:url");
|
|
@@ -13,7 +12,7 @@ const dirname = node_path_1.default.dirname((0, node_url_1.fileURLToPath)(import
|
|
|
13
12
|
const pathToImgDir = node_path_1.default.join(dirname, "../img");
|
|
14
13
|
exports.faviconPlugin = (0, fastify_plugin_1.default)(async (instance) => {
|
|
15
14
|
console.log("pathToImgDir", pathToImgDir);
|
|
16
|
-
instance.register(
|
|
15
|
+
// instance.register(fastifyFavicon, { path: pathToImgDir });
|
|
17
16
|
}, {
|
|
18
17
|
name: "favicon-plugin",
|
|
19
18
|
});
|
|
@@ -8,4 +8,7 @@ type SymbolicatePluginOptions = {
|
|
|
8
8
|
onSymbolicate: (request: SymbolicateRequest, reply: SymbolicateReply) => void;
|
|
9
9
|
};
|
|
10
10
|
export declare const symbolicatePlugin: import("fastify").FastifyPluginCallback<SymbolicatePluginOptions, import("fastify").RawServerDefault, import("fastify").FastifyTypeProviderDefault, import("fastify").FastifyBaseLogger>;
|
|
11
|
+
export declare const rawBodyPlugin: import("fastify").FastifyPluginCallback<{
|
|
12
|
+
rawBody: string;
|
|
13
|
+
}, import("fastify").RawServerDefault, import("fastify").FastifyTypeProviderDefault, import("fastify").FastifyBaseLogger>;
|
|
11
14
|
export {};
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.symbolicatePlugin = void 0;
|
|
6
|
+
exports.rawBodyPlugin = exports.symbolicatePlugin = void 0;
|
|
7
7
|
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
8
|
exports.symbolicatePlugin = (0, fastify_plugin_1.default)(async (instance, options) => {
|
|
9
9
|
instance.log.info("Symbolicate plugin registered");
|
|
@@ -28,3 +28,9 @@ exports.symbolicatePlugin = (0, fastify_plugin_1.default)(async (instance, optio
|
|
|
28
28
|
name: "symbolicate-plugin",
|
|
29
29
|
dependencies: ["@fastify/sensible"],
|
|
30
30
|
});
|
|
31
|
+
exports.rawBodyPlugin = (0, fastify_plugin_1.default)((instance, options) => {
|
|
32
|
+
instance.addHook("preHandler", (request, reply, next) => {
|
|
33
|
+
// request.rawBody = "";
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { TerminalReportableEvent } from "metro/src/lib/TerminalReporter";
|
|
2
2
|
import type { DevServer } from "../dev-server/dev-server";
|
|
3
3
|
import { BaseTerminalReporter } from "./base.terminal.reporter";
|
|
4
|
-
|
|
4
|
+
import { EventReporter, ReportableEvent } from "../dev-server/inspector/types";
|
|
5
|
+
export declare class TeardownTerminalReporter extends BaseTerminalReporter implements EventReporter {
|
|
5
6
|
readonly devServer: DevServer;
|
|
6
7
|
constructor(devServer: DevServer);
|
|
7
8
|
_log(event: TerminalReportableEvent): void;
|
|
@@ -9,4 +10,5 @@ export declare class TeardownTerminalReporter extends BaseTerminalReporter {
|
|
|
9
10
|
dependencyGraphLoading(hasReducedPerformance: boolean): void;
|
|
10
11
|
_logWorkerChunk(origin: "stdout" | "stderr", chunk: string): void;
|
|
11
12
|
update(event: TerminalReportableEvent): void;
|
|
13
|
+
logEvent(event: ReportableEvent): void;
|
|
12
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teardown/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.30",
|
|
4
4
|
"description": "Teardown CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"@fastify/cors": "^10.0.1",
|
|
24
24
|
"@fastify/middie": "^9.0.2",
|
|
25
25
|
"@fastify/sensible": "^6.0.1",
|
|
26
|
+
"@isaacs/ttlcache": "^1.4.1",
|
|
26
27
|
"@react-native-community/cli-server-api": "^15.0.1",
|
|
27
|
-
"@react-native/dev-middleware": "0.76.1",
|
|
28
28
|
"@react-native/metro-config": "0.76.1",
|
|
29
29
|
"@types/bun": "^1.1.13",
|
|
30
30
|
"bun": "1.1.34",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"metro": "^0.81.0",
|
|
43
43
|
"metro-config": "^0.81.0",
|
|
44
44
|
"metro-core": "^0.81.0",
|
|
45
|
-
"metro-runtime": "^0.81.0",
|
|
46
45
|
"pretty-format": "^29.7.0",
|
|
47
46
|
"prompts": "^2.4.2",
|
|
48
|
-
"source-map": "^0.7.4"
|
|
47
|
+
"source-map": "^0.7.4",
|
|
48
|
+
"timers": "^0.1.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/babel__code-frame": "^7.0.6",
|