@teardown/cli 1.2.20 → 1.2.23
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/bin/teardown.js +3 -0
- package/dist/commands/dev/dev.d.ts +22 -0
- package/dist/commands/dev/dev.js +55 -0
- package/dist/commands/dev/types.d.ts +64 -0
- package/dist/commands/dev/types.js +2 -0
- package/dist/index.js +11 -32
- package/dist/modules/dev/dev-menu/keyboard-handler.d.ts +20 -0
- package/dist/modules/dev/dev-menu/keyboard-handler.js +126 -0
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.d.ts +18 -0
- package/dist/modules/dev/dev-menu/open-debugger-keyboard-handler.js +105 -0
- package/dist/modules/dev/dev-server/dev-server-checker.d.ts +22 -0
- package/dist/modules/dev/dev-server/dev-server-checker.js +72 -0
- package/dist/modules/dev/dev-server/dev-server.d.ts +68 -0
- package/dist/modules/dev/dev-server/dev-server.js +220 -0
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.d.ts +10 -0
- package/dist/modules/dev/dev-server/plugins/devtools.plugin.js +50 -0
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.d.ts +1 -0
- package/dist/modules/dev/dev-server/plugins/favicon.plugin.js +19 -0
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.d.ts +1 -0
- package/dist/modules/dev/dev-server/plugins/multipart.plugin.js +62 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/index.d.ts +2 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/index.js +18 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/sybmolicatePlugin.d.ts +1 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/sybmolicatePlugin.js +24 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/types.d.ts +64 -0
- package/dist/modules/dev/dev-server/plugins/symbolicate/types.js +2 -0
- package/dist/modules/dev/dev-server/plugins/types.d.ts +11 -0
- package/dist/modules/dev/dev-server/plugins/types.js +2 -0
- package/dist/modules/dev/dev-server/plugins/wss/index.d.ts +3 -0
- package/dist/modules/dev/dev-server/plugins/wss/index.js +19 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.d.ts +32 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-api.server.js +61 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.d.ts +63 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-debugger.server.js +128 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.d.ts +32 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-dev-client.server.js +75 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.d.ts +75 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-events.server.js +190 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.d.ts +44 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-hmr.server.js +112 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.d.ts +139 -0
- package/dist/modules/dev/dev-server/plugins/wss/servers/web-socket-message.server.js +352 -0
- package/dist/modules/dev/dev-server/plugins/wss/types.d.ts +6 -0
- package/dist/modules/dev/dev-server/plugins/wss/types.js +2 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.d.ts +32 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-router.js +59 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.d.ts +13 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server-adapter.js +26 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.d.ts +39 -0
- package/dist/modules/dev/dev-server/plugins/wss/web-socket-server.js +46 -0
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.d.ts +46 -0
- package/dist/modules/dev/dev-server/plugins/wss/wss.plugin.js +57 -0
- package/dist/modules/dev/dev-server/types.d.ts +27 -0
- package/dist/modules/dev/dev-server/types.js +17 -0
- package/dist/modules/dev/terminal/base.terminal.reporter.d.ts +25 -0
- package/dist/modules/dev/terminal/base.terminal.reporter.js +78 -0
- package/dist/modules/dev/terminal/terminal.reporter.d.ts +12 -0
- package/dist/modules/dev/terminal/terminal.reporter.js +71 -0
- package/dist/modules/dev/types.d.ts +20 -0
- package/dist/modules/dev/types.js +2 -0
- package/dist/modules/dev/utils/log.d.ts +23 -0
- package/dist/modules/dev/utils/log.js +73 -0
- package/package.json +40 -17
- /package/dist/{init-teardown.d.ts → commands/init/init-teardown.d.ts} +0 -0
- /package/dist/{init-teardown.js → commands/init/init-teardown.js} +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
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.DevServer = void 0;
|
|
7
|
+
exports.makeLogEntryFromFastifyLog = makeLogEntryFromFastifyLog;
|
|
8
|
+
const middie_1 = __importDefault(require("@fastify/middie"));
|
|
9
|
+
const sensible_1 = __importDefault(require("@fastify/sensible"));
|
|
10
|
+
const compress_1 = __importDefault(require("@fastify/compress"));
|
|
11
|
+
const cli_server_api_1 = require("@react-native-community/cli-server-api");
|
|
12
|
+
const dev_middleware_1 = require("@react-native/dev-middleware");
|
|
13
|
+
const metro_config_1 = require("@react-native/metro-config");
|
|
14
|
+
const fastify_1 = __importDefault(require("fastify"));
|
|
15
|
+
const metro_1 = __importDefault(require("metro"));
|
|
16
|
+
const node_stream_1 = require("node:stream");
|
|
17
|
+
const terminal_reporter_1 = require("../terminal/terminal.reporter");
|
|
18
|
+
const devtools_plugin_1 = require("./plugins/devtools.plugin");
|
|
19
|
+
// import { faviconPlugin } from "./plugins/favicon.plugin";
|
|
20
|
+
const multipart_plugin_1 = require("./plugins/multipart.plugin");
|
|
21
|
+
const symbolicate_1 = require("./plugins/symbolicate");
|
|
22
|
+
const wss_1 = require("./plugins/wss");
|
|
23
|
+
const web_socket_events_server_1 = require("./plugins/wss/servers/web-socket-events.server");
|
|
24
|
+
const web_socket_message_server_1 = require("./plugins/wss/servers/web-socket-message.server");
|
|
25
|
+
const keyboard_handler_1 = require("../dev-menu/keyboard-handler");
|
|
26
|
+
class DevServer {
|
|
27
|
+
config;
|
|
28
|
+
terminalReporter;
|
|
29
|
+
instance;
|
|
30
|
+
messageServer;
|
|
31
|
+
eventsServer;
|
|
32
|
+
keyboardHandler;
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.terminalReporter = new terminal_reporter_1.TeardownTerminalReporter(this);
|
|
36
|
+
this.instance = (0, fastify_1.default)({
|
|
37
|
+
// disableRequestLogging: false,
|
|
38
|
+
logger: {
|
|
39
|
+
level: "trace",
|
|
40
|
+
stream: new node_stream_1.Writable({
|
|
41
|
+
write: (chunk, _encoding, callback) => {
|
|
42
|
+
const log = JSON.parse(chunk.toString());
|
|
43
|
+
this.onMessage(log);
|
|
44
|
+
this.instance.wss?.apiServer.send(log);
|
|
45
|
+
callback();
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
...(config.https ? { https: config.https } : undefined),
|
|
50
|
+
});
|
|
51
|
+
this.messageServer = new web_socket_message_server_1.WebSocketMessageServer(this.instance);
|
|
52
|
+
this.eventsServer = new web_socket_events_server_1.WebSocketEventsServer(this.instance, {
|
|
53
|
+
webSocketMessageServer: this.messageServer,
|
|
54
|
+
});
|
|
55
|
+
this.keyboardHandler = new keyboard_handler_1.KeyboardHandlerManager(this);
|
|
56
|
+
}
|
|
57
|
+
getDevServerUrl() {
|
|
58
|
+
const https = this.config.https ? "https" : "http";
|
|
59
|
+
return `${https}://${this.config.host}:${this.config.port}`;
|
|
60
|
+
}
|
|
61
|
+
onInitializeDone() {
|
|
62
|
+
this.keyboardHandler.initialize();
|
|
63
|
+
}
|
|
64
|
+
reportMetroEvent(event) {
|
|
65
|
+
// this.messageServer.broadcast("report_event", event);
|
|
66
|
+
// console.log("Metro event", event);
|
|
67
|
+
}
|
|
68
|
+
onBundleBuilt(bundlePath) {
|
|
69
|
+
console.log("onBundleBuilt", bundlePath);
|
|
70
|
+
}
|
|
71
|
+
onMessage(log) {
|
|
72
|
+
this.terminalReporter.update({
|
|
73
|
+
type: "client_log",
|
|
74
|
+
level: "info",
|
|
75
|
+
data: [log.msg],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
onClientConnected(platform, clientId) {
|
|
79
|
+
console.log("onClientConnected", platform, clientId);
|
|
80
|
+
// this.instance.wss.router.onClientConnected(platform, clientId);
|
|
81
|
+
// this.onMessage({
|
|
82
|
+
// level: 30,
|
|
83
|
+
// time: Date.now(),
|
|
84
|
+
// pid: 1,
|
|
85
|
+
// hostname: "localhost",
|
|
86
|
+
// });
|
|
87
|
+
}
|
|
88
|
+
async loadMetroConfig() {
|
|
89
|
+
const config = await metro_1.default.loadConfig({
|
|
90
|
+
cwd: this.config.projectRoot,
|
|
91
|
+
...this.config,
|
|
92
|
+
});
|
|
93
|
+
const reactNativeConfig = (0, metro_config_1.getDefaultConfig)(this.config.projectRoot);
|
|
94
|
+
return (0, metro_config_1.mergeConfig)(reactNativeConfig, config);
|
|
95
|
+
}
|
|
96
|
+
_metroConfig = null;
|
|
97
|
+
async getMetroConfig() {
|
|
98
|
+
if (!this._metroConfig) {
|
|
99
|
+
this._metroConfig = await this.loadMetroConfig();
|
|
100
|
+
}
|
|
101
|
+
return (0, metro_config_1.mergeConfig)(this._metroConfig, {
|
|
102
|
+
reporter: this.terminalReporter,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async registerPlugins() {
|
|
106
|
+
const metroConfig = await this.getMetroConfig();
|
|
107
|
+
const serverInstance = await metro_1.default.createConnectMiddleware(metroConfig, {
|
|
108
|
+
watch: true,
|
|
109
|
+
onBundleBuilt: this.onBundleBuilt.bind(this),
|
|
110
|
+
});
|
|
111
|
+
// console.log("Registering plugins");
|
|
112
|
+
const devMiddleware = (0, dev_middleware_1.createDevMiddleware)({
|
|
113
|
+
projectRoot: this.config.projectRoot,
|
|
114
|
+
serverBaseUrl: `http://${this.config.host}:${this.config.port}`,
|
|
115
|
+
logger: this.instance.log,
|
|
116
|
+
unstable_experiments: {
|
|
117
|
+
// enableNewDebugger: this.config.experiments?.experimentalDebugger,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
await this.instance.register(compress_1.default);
|
|
121
|
+
await this.instance.register(sensible_1.default);
|
|
122
|
+
await this.instance.register(middie_1.default);
|
|
123
|
+
await this.instance.register(wss_1.wssPlugin, {
|
|
124
|
+
metroConfig,
|
|
125
|
+
metroServer: serverInstance.metroServer,
|
|
126
|
+
onClientConnected: this.onClientConnected.bind(this),
|
|
127
|
+
messageServer: this.messageServer,
|
|
128
|
+
eventsServer: this.eventsServer,
|
|
129
|
+
endpoints: {
|
|
130
|
+
"/inspector/debug": devMiddleware.websocketEndpoints["/inspector/debug"],
|
|
131
|
+
"/inspector/device": devMiddleware.websocketEndpoints["/inspector/device"],
|
|
132
|
+
"/inspector/network": devMiddleware.websocketEndpoints["/inspector/debug"], // Uses same endpoint as debugger to handle Network-related CDP events
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
await this.instance.register(multipart_plugin_1.multipartPlugin);
|
|
136
|
+
await this.instance.register(devtools_plugin_1.devtoolsPlugin, {
|
|
137
|
+
host: this.config.host,
|
|
138
|
+
port: this.config.port,
|
|
139
|
+
https: this.config.https,
|
|
140
|
+
});
|
|
141
|
+
await this.instance.register(symbolicate_1.symbolicatePlugin);
|
|
142
|
+
// await this.instance.register(faviconPlugin);
|
|
143
|
+
// Register middleware
|
|
144
|
+
this.instance.use("/open-url", cli_server_api_1.openURLMiddleware);
|
|
145
|
+
this.instance.use("/open-stack-frame", (0, cli_server_api_1.openStackFrameInEditorMiddleware)({
|
|
146
|
+
watchFolders: [this.config.projectRoot],
|
|
147
|
+
}));
|
|
148
|
+
this.instance.use(devMiddleware.middleware);
|
|
149
|
+
// Convert Metro middleware to Fastify middleware format
|
|
150
|
+
this.instance.use((req, res, next) => {
|
|
151
|
+
const middleware = serverInstance.middleware;
|
|
152
|
+
middleware(req, res, next);
|
|
153
|
+
});
|
|
154
|
+
// console.log("Plugins registered");
|
|
155
|
+
}
|
|
156
|
+
registerHooks() {
|
|
157
|
+
// console.log("Registering hooks");
|
|
158
|
+
this.instance.addHook("onSend", async (request, reply, payload) => {
|
|
159
|
+
reply.header("X-Content-Type-Options", "nosniff");
|
|
160
|
+
reply.header("X-React-Native-Project-Root", this.config.projectRoot);
|
|
161
|
+
const [pathname] = request.url.split("?");
|
|
162
|
+
if (pathname.endsWith(".map")) {
|
|
163
|
+
reply.header("Access-Control-Allow-Origin", "devtools://devtools");
|
|
164
|
+
}
|
|
165
|
+
return payload;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
registerRoutes() {
|
|
169
|
+
// console.log("Registering routes");
|
|
170
|
+
this.instance.get("/", async () => "React Native packager is running");
|
|
171
|
+
this.instance.get("/status", async () => "packager-status:running");
|
|
172
|
+
}
|
|
173
|
+
async initialize() {
|
|
174
|
+
console.log("Initializing dev server");
|
|
175
|
+
await this.registerPlugins();
|
|
176
|
+
this.registerHooks();
|
|
177
|
+
this.registerRoutes();
|
|
178
|
+
}
|
|
179
|
+
async start() {
|
|
180
|
+
this.instance.log.info("Starting dev server", this.config);
|
|
181
|
+
await this.instance.listen({
|
|
182
|
+
port: this.config.port,
|
|
183
|
+
host: this.config.host,
|
|
184
|
+
});
|
|
185
|
+
console.log("Dev server started", this.instance.server.address());
|
|
186
|
+
}
|
|
187
|
+
async stop() {
|
|
188
|
+
console.log("Stopping dev server");
|
|
189
|
+
await this.instance.close();
|
|
190
|
+
}
|
|
191
|
+
getInstance() {
|
|
192
|
+
return this.instance;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.DevServer = DevServer;
|
|
196
|
+
const levelToTypeMapping = {
|
|
197
|
+
10: "debug",
|
|
198
|
+
20: "debug",
|
|
199
|
+
30: "info",
|
|
200
|
+
40: "warn",
|
|
201
|
+
50: "error",
|
|
202
|
+
60: "error",
|
|
203
|
+
};
|
|
204
|
+
function makeLogEntryFromFastifyLog(data) {
|
|
205
|
+
const { level, time, pid, hostname, ...rest } = data;
|
|
206
|
+
const levelToTypeMapping = {
|
|
207
|
+
10: "debug",
|
|
208
|
+
20: "debug",
|
|
209
|
+
30: "info",
|
|
210
|
+
40: "warn",
|
|
211
|
+
50: "error",
|
|
212
|
+
60: "error",
|
|
213
|
+
};
|
|
214
|
+
return {
|
|
215
|
+
type: levelToTypeMapping[level] ?? "log",
|
|
216
|
+
timestamp: time,
|
|
217
|
+
issuer: "",
|
|
218
|
+
message: [rest],
|
|
219
|
+
};
|
|
220
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Options = {
|
|
2
|
+
host: string | undefined;
|
|
3
|
+
port: number;
|
|
4
|
+
https?: {
|
|
5
|
+
key: string;
|
|
6
|
+
cert: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare const devtoolsPlugin: import("fastify").FastifyPluginCallback<Options, import("fastify").RawServerDefault, import("fastify").FastifyTypeProviderDefault, import("fastify").FastifyBaseLogger>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
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.devtoolsPlugin = void 0;
|
|
7
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
|
+
const open_1 = __importDefault(require("open"));
|
|
9
|
+
exports.devtoolsPlugin = (0, fastify_plugin_1.default)(async (instance, options) => {
|
|
10
|
+
instance.route({
|
|
11
|
+
method: ["GET", "POST", "PUT"],
|
|
12
|
+
url: "/reload",
|
|
13
|
+
handler: (_request, reply) => {
|
|
14
|
+
console.log("Reload endpoint hit", instance.wss.messageServer.broadcast != null);
|
|
15
|
+
instance.wss.messageServer.broadcast("reload");
|
|
16
|
+
reply.send("OK");
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
instance.route({
|
|
20
|
+
method: ["GET", "POST", "PUT"],
|
|
21
|
+
url: "/launch-js-devtools",
|
|
22
|
+
handler: async (request, reply) => {
|
|
23
|
+
const customDebugger = process.env.REACT_DEBUGGER;
|
|
24
|
+
if (customDebugger) {
|
|
25
|
+
// NOOP for now
|
|
26
|
+
// TODO implement opening teardown here
|
|
27
|
+
}
|
|
28
|
+
else if (!instance.wss.debuggerServer.isDebuggerConnected()) {
|
|
29
|
+
const url = `${options.https ? "https" : "http"}://${options.host || "localhost"}:${options.port}/debugger-ui`;
|
|
30
|
+
try {
|
|
31
|
+
request.log.info({ msg: "Opening debugger UI", url });
|
|
32
|
+
await (0, open_1.default)(url);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error) {
|
|
36
|
+
request.log.error({
|
|
37
|
+
msg: "Cannot open debugger UI",
|
|
38
|
+
url,
|
|
39
|
+
error,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
reply.send("OK");
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}, {
|
|
48
|
+
name: "devtools-plugin",
|
|
49
|
+
dependencies: ["wss-plugin"],
|
|
50
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const faviconPlugin: (instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>) => Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
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.faviconPlugin = void 0;
|
|
7
|
+
const fastify_favicon_1 = __importDefault(require("fastify-favicon"));
|
|
8
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_url_1 = require("node:url");
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
const dirname = node_path_1.default.dirname((0, node_url_1.fileURLToPath)(import.meta.url));
|
|
13
|
+
const pathToImgDir = node_path_1.default.join(dirname, "../img");
|
|
14
|
+
exports.faviconPlugin = (0, fastify_plugin_1.default)(async (instance) => {
|
|
15
|
+
console.log("pathToImgDir", pathToImgDir);
|
|
16
|
+
instance.register(fastify_favicon_1.default, { path: pathToImgDir });
|
|
17
|
+
}, {
|
|
18
|
+
name: "favicon-plugin",
|
|
19
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const multipartPlugin: (instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>) => Promise<void>;
|
|
@@ -0,0 +1,62 @@
|
|
|
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.multipartPlugin = void 0;
|
|
7
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
|
+
const node_stream_1 = require("node:stream");
|
|
9
|
+
/**
|
|
10
|
+
* Implementation is based on:
|
|
11
|
+
* https://github.com/facebook/metro/blob/347b1d7ed87995d7951aaa9fd597c04b06013dac/packages/metro/src/Server/MultipartResponse.js
|
|
12
|
+
*/
|
|
13
|
+
const CRLF = "\r\n";
|
|
14
|
+
const BOUNDARY = "3beqjf3apnqeu3h5jqorms4i";
|
|
15
|
+
exports.multipartPlugin = (0, fastify_plugin_1.default)(async (instance) => {
|
|
16
|
+
function asMultipart() {
|
|
17
|
+
// We should check if is included in accept or if accept has multipart/* or */*,
|
|
18
|
+
// but React Native will set accept to exactly `multipart/mixed`, so a simple check
|
|
19
|
+
// will suffice.
|
|
20
|
+
if (this.request.headers.accept !== "multipart/mixed") {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const headers = {};
|
|
24
|
+
const stream = new node_stream_1.PassThrough();
|
|
25
|
+
this.code(200)
|
|
26
|
+
.header("Content-Type", `multipart/mixed; boundary="${BOUNDARY}"`)
|
|
27
|
+
.send(stream);
|
|
28
|
+
function serializeHeaders(headers) {
|
|
29
|
+
return Object.keys(headers)
|
|
30
|
+
.map((key) => `${key}: ${headers[key]}`)
|
|
31
|
+
.join(CRLF);
|
|
32
|
+
}
|
|
33
|
+
function writeChunk(headers, data, isLast) {
|
|
34
|
+
let chunk = `${CRLF}--${BOUNDARY}${CRLF}`;
|
|
35
|
+
if (headers) {
|
|
36
|
+
chunk += serializeHeaders(headers) + CRLF + CRLF;
|
|
37
|
+
}
|
|
38
|
+
if (data) {
|
|
39
|
+
chunk += data;
|
|
40
|
+
}
|
|
41
|
+
if (isLast) {
|
|
42
|
+
chunk += `${CRLF}--${BOUNDARY}--${CRLF}`;
|
|
43
|
+
}
|
|
44
|
+
stream.write(chunk);
|
|
45
|
+
}
|
|
46
|
+
function setHeader(name, value) {
|
|
47
|
+
headers[name] = value;
|
|
48
|
+
}
|
|
49
|
+
function end(data) {
|
|
50
|
+
writeChunk(headers, data, true);
|
|
51
|
+
stream.end();
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
writeChunk,
|
|
55
|
+
setHeader,
|
|
56
|
+
end,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
instance.decorateReply("asMultipart", asMultipart);
|
|
60
|
+
}, {
|
|
61
|
+
name: "multipart-plugin",
|
|
62
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./sybmolicatePlugin"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const symbolicatePlugin: (instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>) => Promise<void>;
|
|
@@ -0,0 +1,24 @@
|
|
|
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.symbolicatePlugin = void 0;
|
|
7
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
|
+
exports.symbolicatePlugin = (0, fastify_plugin_1.default)(async (instance) => {
|
|
9
|
+
instance.post("/symbolicate", async (request, reply) => {
|
|
10
|
+
instance.log.info("Symbolicate endpoint hit", request.body);
|
|
11
|
+
const requestWithBody = request;
|
|
12
|
+
requestWithBody.rawBody = "";
|
|
13
|
+
requestWithBody.raw.setEncoding("utf8");
|
|
14
|
+
request.raw.on("data", (chunk) => {
|
|
15
|
+
requestWithBody.rawBody += chunk;
|
|
16
|
+
});
|
|
17
|
+
requestWithBody.raw.on("end", () => {
|
|
18
|
+
reply.send(requestWithBody.rawBody);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}, {
|
|
22
|
+
name: "symbolicate-plugin",
|
|
23
|
+
dependencies: ["@fastify/sensible"],
|
|
24
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw React Native stack frame.
|
|
3
|
+
*/
|
|
4
|
+
export interface ReactNativeStackFrame {
|
|
5
|
+
lineNumber: number | null;
|
|
6
|
+
column: number | null;
|
|
7
|
+
file: string | null;
|
|
8
|
+
methodName: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* React Native stack frame used as input when processing by {@link Symbolicator}.
|
|
12
|
+
*/
|
|
13
|
+
export interface InputStackFrame extends ReactNativeStackFrame {
|
|
14
|
+
file: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Final symbolicated stack frame.
|
|
18
|
+
*/
|
|
19
|
+
export interface StackFrame extends InputStackFrame {
|
|
20
|
+
collapse: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Represents [@babel/core-frame](https://babeljs.io/docs/en/babel-code-frame).
|
|
24
|
+
*/
|
|
25
|
+
export interface CodeFrame {
|
|
26
|
+
content: string;
|
|
27
|
+
location: {
|
|
28
|
+
row: number;
|
|
29
|
+
column: number;
|
|
30
|
+
};
|
|
31
|
+
fileName: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Represents results of running {@link process} method on {@link Symbolicator} instance.
|
|
35
|
+
*/
|
|
36
|
+
export interface SymbolicatorResults {
|
|
37
|
+
codeFrame: CodeFrame | null;
|
|
38
|
+
stack: StackFrame[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Delegate with implementation for symbolication functions.
|
|
42
|
+
*/
|
|
43
|
+
export interface SymbolicatorDelegate {
|
|
44
|
+
/**
|
|
45
|
+
* Get source code of file in the URL.
|
|
46
|
+
*
|
|
47
|
+
* @param fileUrl A full URL pointing to a file.
|
|
48
|
+
*/
|
|
49
|
+
getSource: (fileUrl: string) => Promise<string | Buffer>;
|
|
50
|
+
/**
|
|
51
|
+
* Get source map for the file in the URL.
|
|
52
|
+
*
|
|
53
|
+
* @param fileUrl A full (usually `http:`) URL pointing to a compiled file.
|
|
54
|
+
* The URL points to a file for which to return source map, not to the source map file itself,
|
|
55
|
+
* e.g: `http://localhost:8081/index.bundle?platform=ios`.
|
|
56
|
+
*/
|
|
57
|
+
getSourceMap: (fileUrl: string) => Promise<string | Buffer>;
|
|
58
|
+
/**
|
|
59
|
+
* Check if given stack frame should be included in the new symbolicated stack.
|
|
60
|
+
*
|
|
61
|
+
* @param frame Stack frame to check.
|
|
62
|
+
*/
|
|
63
|
+
shouldIncludeFrame: (frame: StackFrame) => boolean;
|
|
64
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from 'node:http';
|
|
2
|
+
export interface MultipartHandler {
|
|
3
|
+
writeChunk: <T>(headers: IncomingHttpHeaders, data: T, isLast?: boolean) => void;
|
|
4
|
+
setHeader: (name: string, value: string | string[] | undefined) => void;
|
|
5
|
+
end: <T>(data: T) => void;
|
|
6
|
+
}
|
|
7
|
+
declare module 'fastify' {
|
|
8
|
+
interface FastifyReply {
|
|
9
|
+
asMultipart: () => MultipartHandler | undefined;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./wss.plugin"), exports);
|
|
18
|
+
__exportStar(require("./web-socket-server"), exports);
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type WebSocket from "ws";
|
|
3
|
+
import { WebSocketServer } from "../web-socket-server";
|
|
4
|
+
/**
|
|
5
|
+
* Class for creating a WebSocket server for API clients.
|
|
6
|
+
* Useful to listening for compilation events and new logs.
|
|
7
|
+
*
|
|
8
|
+
* @category Development server
|
|
9
|
+
*/
|
|
10
|
+
export declare class WebSocketApiServer extends WebSocketServer {
|
|
11
|
+
private clients;
|
|
12
|
+
private nextClientId;
|
|
13
|
+
/**
|
|
14
|
+
* Create new instance of WebSocketApiServer and attach it to the given Fastify instance.
|
|
15
|
+
* Any logging information, will be passed through standard `fastify.log` API.
|
|
16
|
+
*
|
|
17
|
+
* @param fastify Fastify instance to attach the WebSocket server to.
|
|
18
|
+
*/
|
|
19
|
+
constructor(fastify: FastifyInstance);
|
|
20
|
+
/**
|
|
21
|
+
* Send message to all connected API clients.
|
|
22
|
+
*
|
|
23
|
+
* @param event Event string or object to send.
|
|
24
|
+
*/
|
|
25
|
+
send(event: any): void;
|
|
26
|
+
/**
|
|
27
|
+
* Process new WebSocket connection from client application.
|
|
28
|
+
*
|
|
29
|
+
* @param socket Incoming client's WebSocket connection.
|
|
30
|
+
*/
|
|
31
|
+
onConnection(socket: WebSocket): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSocketApiServer = void 0;
|
|
4
|
+
const web_socket_server_1 = require("../web-socket-server");
|
|
5
|
+
/**
|
|
6
|
+
* Class for creating a WebSocket server for API clients.
|
|
7
|
+
* Useful to listening for compilation events and new logs.
|
|
8
|
+
*
|
|
9
|
+
* @category Development server
|
|
10
|
+
*/
|
|
11
|
+
class WebSocketApiServer extends web_socket_server_1.WebSocketServer {
|
|
12
|
+
clients = new Map();
|
|
13
|
+
nextClientId = 0;
|
|
14
|
+
/**
|
|
15
|
+
* Create new instance of WebSocketApiServer and attach it to the given Fastify instance.
|
|
16
|
+
* Any logging information, will be passed through standard `fastify.log` API.
|
|
17
|
+
*
|
|
18
|
+
* @param fastify Fastify instance to attach the WebSocket server to.
|
|
19
|
+
*/
|
|
20
|
+
constructor(fastify) {
|
|
21
|
+
super(fastify, "/api-console");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Send message to all connected API clients.
|
|
25
|
+
*
|
|
26
|
+
* @param event Event string or object to send.
|
|
27
|
+
*/
|
|
28
|
+
send(event) {
|
|
29
|
+
const data = typeof event === "string" ? event : JSON.stringify(event);
|
|
30
|
+
for (const [, socket] of this.clients.entries()) {
|
|
31
|
+
try {
|
|
32
|
+
socket.send(data);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// NOOP
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Process new WebSocket connection from client application.
|
|
41
|
+
*
|
|
42
|
+
* @param socket Incoming client's WebSocket connection.
|
|
43
|
+
*/
|
|
44
|
+
onConnection(socket) {
|
|
45
|
+
const clientId = `client#${this.nextClientId++}`;
|
|
46
|
+
console.log("WebSocketApiServer onConnection", clientId, socket);
|
|
47
|
+
this.clients.set(clientId, socket);
|
|
48
|
+
this.fastify.log.debug({ msg: "API client connected", clientId });
|
|
49
|
+
this.clients.set(clientId, socket);
|
|
50
|
+
const onClose = () => {
|
|
51
|
+
this.fastify.log.debug({
|
|
52
|
+
msg: "API client disconnected",
|
|
53
|
+
clientId,
|
|
54
|
+
});
|
|
55
|
+
this.clients.delete(clientId);
|
|
56
|
+
};
|
|
57
|
+
socket.addEventListener("error", onClose);
|
|
58
|
+
socket.addEventListener("close", onClose);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.WebSocketApiServer = WebSocketApiServer;
|