@callstack/repack-dev-server 5.3.0 → 5.4.0-canary-20260831210904
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/createServer.d.ts +1 -1
- package/dist/createServer.js +0 -1
- package/dist/plugins/devtools/devtoolsPlugin.js +5 -2
- package/dist/plugins/symbolicate/Symbolicator.d.ts +0 -5
- package/dist/plugins/symbolicate/Symbolicator.js +58 -48
- package/dist/plugins/symbolicate/index.d.ts +1 -1
- package/dist/plugins/symbolicate/index.js +1 -1
- package/dist/plugins/symbolicate/logSymbolicatedStackFrame.d.ts +3 -0
- package/dist/plugins/symbolicate/logSymbolicatedStackFrame.js +42 -0
- package/dist/plugins/symbolicate/sybmolicatePlugin.js +2 -0
- package/dist/plugins/wss/WebSocketServer.d.ts +1 -1
- package/dist/plugins/wss/WebSocketServer.js +4 -2
- package/dist/plugins/wss/index.d.ts +2 -2
- package/dist/plugins/wss/index.js +2 -2
- package/dist/plugins/wss/servers/WebSocketMessageServer.js +1 -1
- package/dist/plugins/wss/wssPlugin.d.ts +2 -2
- package/dist/plugins/wss/wssPlugin.js +2 -2
- package/dist/types.d.ts +7 -2
- package/dist/utils/symbolication.d.ts +10 -0
- package/dist/utils/symbolication.js +51 -0
- package/package.json +2 -2
package/dist/createServer.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export declare function createServer(config: Server.Config): Promise<{
|
|
|
10
10
|
start: () => Promise<void>;
|
|
11
11
|
stop: () => Promise<void>;
|
|
12
12
|
instance: Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault> & PromiseLike<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>> & {
|
|
13
|
-
__linterBrands:
|
|
13
|
+
__linterBrands: 'SafePromiseLike';
|
|
14
14
|
};
|
|
15
15
|
}>;
|
package/dist/createServer.js
CHANGED
|
@@ -21,7 +21,6 @@ import { normalizeOptions } from './utils/normalizeOptions.js';
|
|
|
21
21
|
* @returns `start` and `stop` functions as well as an underlying Fastify `instance`.
|
|
22
22
|
*/
|
|
23
23
|
export async function createServer(config) {
|
|
24
|
-
// biome-ignore lint/style/useConst: needed in fastify constructor
|
|
25
24
|
let delegate;
|
|
26
25
|
const options = normalizeOptions(config.options);
|
|
27
26
|
/** Fastify instance powering the development server. */
|
|
@@ -27,8 +27,11 @@ async function devtoolsPlugin(instance, { delegate }) {
|
|
|
27
27
|
url: '/open-stack-frame',
|
|
28
28
|
handler: async (request, reply) => {
|
|
29
29
|
const { file, lineNumber } = parseRequestBody(request.body);
|
|
30
|
-
const
|
|
31
|
-
|
|
30
|
+
const openedRemotely = await delegate.devTools?.openStackFrame?.(file, lineNumber);
|
|
31
|
+
if (!openedRemotely) {
|
|
32
|
+
const filepath = delegate.devTools?.resolveProjectPath(file) ?? file;
|
|
33
|
+
launchEditor(`${filepath}:${lineNumber}`, process.env.REACT_EDITOR);
|
|
34
|
+
}
|
|
32
35
|
reply.send('OK');
|
|
33
36
|
},
|
|
34
37
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { FastifyBaseLogger } from 'fastify';
|
|
2
|
-
import { SourceMapConsumer } from 'source-map';
|
|
3
2
|
import type { ReactNativeStackFrame, SymbolicatorDelegate, SymbolicatorResults } from './types.js';
|
|
4
3
|
/**
|
|
5
4
|
* Class for transforming stack traces from React Native application with using Source Map.
|
|
@@ -18,10 +17,6 @@ export declare class Symbolicator {
|
|
|
18
17
|
* @returns Inferred platform or `undefined` if cannot infer.
|
|
19
18
|
*/
|
|
20
19
|
static inferPlatformFromStack(stack: ReactNativeStackFrame[]): string | undefined;
|
|
21
|
-
/**
|
|
22
|
-
* Cache with initialized `SourceMapConsumer` to improve symbolication performance.
|
|
23
|
-
*/
|
|
24
|
-
sourceMapConsumerCache: Record<string, SourceMapConsumer>;
|
|
25
20
|
/**
|
|
26
21
|
* Constructs new `Symbolicator` instance.
|
|
27
22
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { URL } from 'node:url';
|
|
2
2
|
import { codeFrameColumns } from '@babel/code-frame';
|
|
3
3
|
import { SourceMapConsumer } from 'source-map';
|
|
4
|
+
import { isGeneratedBundleFrame, isSymbolicatableFrame, normalizeInvalidWebpackSourceUrls, } from '../../utils/symbolication.js';
|
|
4
5
|
/**
|
|
5
6
|
* Class for transforming stack traces from React Native application with using Source Map.
|
|
6
7
|
* Raw stack frames produced by React Native, points to some location from the bundle
|
|
@@ -40,10 +41,6 @@ export class Symbolicator {
|
|
|
40
41
|
*/
|
|
41
42
|
constructor(delegate) {
|
|
42
43
|
this.delegate = delegate;
|
|
43
|
-
/**
|
|
44
|
-
* Cache with initialized `SourceMapConsumer` to improve symbolication performance.
|
|
45
|
-
*/
|
|
46
|
-
this.sourceMapConsumerCache = {};
|
|
47
44
|
}
|
|
48
45
|
/**
|
|
49
46
|
* Process raw React Native stack frames and transform them using Source Maps.
|
|
@@ -59,72 +56,78 @@ export class Symbolicator {
|
|
|
59
56
|
*/
|
|
60
57
|
async process(logger, stack) {
|
|
61
58
|
logger.debug({ msg: 'Filtering out unnecessary frames' });
|
|
62
|
-
const frames =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
}
|
|
59
|
+
const frames = stack.filter(isSymbolicatableFrame);
|
|
60
|
+
// A Symbolicator instance is shared by the route. Keep consumers local to
|
|
61
|
+
// one request so concurrent call-stack and component-stack requests cannot
|
|
62
|
+
// destroy or read each other's source maps.
|
|
63
|
+
const sourceMapConsumers = new Map();
|
|
69
64
|
try {
|
|
70
65
|
logger.debug({ msg: 'Processing frames', frames });
|
|
71
66
|
const processedFrames = [];
|
|
72
67
|
for (const frame of frames) {
|
|
73
|
-
|
|
68
|
+
try {
|
|
69
|
+
if (!sourceMapConsumers.has(frame.file)) {
|
|
70
|
+
logger.debug({
|
|
71
|
+
msg: 'Loading raw source map data',
|
|
72
|
+
fileUrl: frame.file,
|
|
73
|
+
});
|
|
74
|
+
const rawSourceMap = await this.delegate.getSourceMap(frame.file);
|
|
75
|
+
logger.debug({
|
|
76
|
+
msg: 'Creating source map instance',
|
|
77
|
+
fileUrl: frame.file,
|
|
78
|
+
sourceMapLength: rawSourceMap.length,
|
|
79
|
+
});
|
|
80
|
+
const sourceMapConsumer = await new SourceMapConsumer(normalizeInvalidWebpackSourceUrls(rawSourceMap));
|
|
81
|
+
logger.debug({
|
|
82
|
+
msg: 'Saving source map instance into cache',
|
|
83
|
+
fileUrl: frame.file,
|
|
84
|
+
});
|
|
85
|
+
sourceMapConsumers.set(frame.file, sourceMapConsumer);
|
|
86
|
+
}
|
|
74
87
|
logger.debug({
|
|
75
|
-
msg: '
|
|
76
|
-
|
|
88
|
+
msg: 'Symbolicating frame',
|
|
89
|
+
frame,
|
|
77
90
|
});
|
|
78
|
-
const
|
|
91
|
+
const processedFrame = this.processFrame(frame, sourceMapConsumers);
|
|
79
92
|
logger.debug({
|
|
80
|
-
msg: '
|
|
81
|
-
|
|
82
|
-
sourceMapLength: rawSourceMap.length,
|
|
93
|
+
msg: 'Finished symbolicating frame',
|
|
94
|
+
frame,
|
|
83
95
|
});
|
|
84
|
-
|
|
96
|
+
processedFrames.push(processedFrame);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Match Metro's best-effort behavior: one unavailable or malformed
|
|
100
|
+
// source map must not discard frames that can still be symbolicated.
|
|
85
101
|
logger.debug({
|
|
86
|
-
msg: '
|
|
102
|
+
msg: 'Failed to symbolicate frame',
|
|
87
103
|
fileUrl: frame.file,
|
|
104
|
+
error: error.message,
|
|
88
105
|
});
|
|
89
|
-
|
|
106
|
+
processedFrames.push({ ...frame, collapse: false });
|
|
90
107
|
}
|
|
91
|
-
logger.debug({
|
|
92
|
-
msg: 'Symbolicating frame',
|
|
93
|
-
frame,
|
|
94
|
-
});
|
|
95
|
-
const processedFrame = this.processFrame(frame);
|
|
96
|
-
logger.debug({
|
|
97
|
-
msg: 'Finished symbolicating frame',
|
|
98
|
-
frame,
|
|
99
|
-
});
|
|
100
|
-
processedFrames.push(processedFrame);
|
|
101
108
|
}
|
|
102
|
-
const codeFrame = (await this.getCodeFrame(logger, processedFrames)) ?? null;
|
|
109
|
+
const codeFrame = (await this.getCodeFrame(logger, processedFrames, frames, sourceMapConsumers)) ?? null;
|
|
103
110
|
logger.debug({
|
|
104
111
|
msg: 'Finished symbolicating frames',
|
|
105
112
|
processedFrames,
|
|
106
113
|
codeFrame,
|
|
107
114
|
});
|
|
108
|
-
return {
|
|
109
|
-
stack: processedFrames,
|
|
110
|
-
codeFrame,
|
|
111
|
-
};
|
|
115
|
+
return { stack: processedFrames, codeFrame };
|
|
112
116
|
}
|
|
113
117
|
finally {
|
|
114
|
-
for (const
|
|
115
|
-
|
|
116
|
-
delete this.sourceMapConsumerCache[key];
|
|
118
|
+
for (const consumer of sourceMapConsumers.values()) {
|
|
119
|
+
consumer.destroy();
|
|
117
120
|
}
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
|
-
processFrame(frame) {
|
|
121
|
-
if (
|
|
123
|
+
processFrame(frame, sourceMapConsumers) {
|
|
124
|
+
if (frame.lineNumber == null || frame.column == null) {
|
|
122
125
|
return {
|
|
123
126
|
...frame,
|
|
124
127
|
collapse: false,
|
|
125
128
|
};
|
|
126
129
|
}
|
|
127
|
-
const consumer =
|
|
130
|
+
const consumer = sourceMapConsumers.get(frame.file);
|
|
128
131
|
if (!consumer) {
|
|
129
132
|
return {
|
|
130
133
|
...frame,
|
|
@@ -152,16 +155,19 @@ export class Symbolicator {
|
|
|
152
155
|
};
|
|
153
156
|
}
|
|
154
157
|
return {
|
|
155
|
-
lineNumber: lookup.line
|
|
156
|
-
column: lookup.column
|
|
158
|
+
lineNumber: lookup.line ?? frame.lineNumber,
|
|
159
|
+
column: lookup.column ?? frame.column,
|
|
157
160
|
file: lookup.source,
|
|
158
161
|
methodName: lookup.name || frame.methodName,
|
|
159
162
|
collapse: false,
|
|
160
163
|
};
|
|
161
164
|
}
|
|
162
|
-
async getCodeFrame(logger, processedFrames) {
|
|
163
|
-
for (const frame of processedFrames) {
|
|
164
|
-
if (frame.collapse ||
|
|
165
|
+
async getCodeFrame(logger, processedFrames, inputFrames, sourceMapConsumers) {
|
|
166
|
+
for (const [index, frame] of processedFrames.entries()) {
|
|
167
|
+
if (frame.collapse || frame.lineNumber == null || frame.column == null) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (isGeneratedBundleFrame(frame)) {
|
|
165
171
|
continue;
|
|
166
172
|
}
|
|
167
173
|
if (!this.delegate.shouldIncludeFrame(frame)) {
|
|
@@ -172,8 +178,12 @@ export class Symbolicator {
|
|
|
172
178
|
frame,
|
|
173
179
|
});
|
|
174
180
|
try {
|
|
181
|
+
const consumer = sourceMapConsumers.get(inputFrames[index]?.file);
|
|
182
|
+
const embeddedSource = consumer?.sourceContentFor(frame.file, true);
|
|
183
|
+
const source = embeddedSource ??
|
|
184
|
+
(await this.delegate.getSource(frame.file)).toString();
|
|
175
185
|
return {
|
|
176
|
-
content: codeFrameColumns(
|
|
186
|
+
content: codeFrameColumns(source, {
|
|
177
187
|
start: { column: frame.column, line: frame.lineNumber },
|
|
178
188
|
}, { forceColor: true }),
|
|
179
189
|
location: {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { FastifyBaseLogger } from 'fastify';
|
|
2
|
+
import type { ReactNativeStackFrame, SymbolicatorResults } from './types.js';
|
|
3
|
+
export declare function logSymbolicatedStackFrame(logger: FastifyBaseLogger, inputStack: ReactNativeStackFrame[], results: SymbolicatorResults): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isGeneratedBundleFrame, isSymbolicatableFrame, } from '../../utils/symbolication.js';
|
|
2
|
+
const RUNTIME_ERROR_METHODS = new Set([
|
|
3
|
+
'react-stack-bottom-frame',
|
|
4
|
+
'renderWithHooks',
|
|
5
|
+
'beginWork',
|
|
6
|
+
'performUnitOfWork',
|
|
7
|
+
]);
|
|
8
|
+
function isRuntimeErrorStack(stack) {
|
|
9
|
+
return stack.some((frame) => RUNTIME_ERROR_METHODS.has(frame.methodName));
|
|
10
|
+
}
|
|
11
|
+
const REMOTE_SOURCE_PATH_PREFIX = '/__repack_source__/';
|
|
12
|
+
function getRemoteName(file) {
|
|
13
|
+
if (!file) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const filename = new URL(file, 'file://').pathname.split('/').pop() ?? '';
|
|
17
|
+
return filename.match(/\.([^.]+)\.chunk\.bundle$/)?.[1];
|
|
18
|
+
}
|
|
19
|
+
function getPrintableFile(file, inputFile) {
|
|
20
|
+
const sourceUrl = new URL(file, 'file://');
|
|
21
|
+
if (sourceUrl.pathname.startsWith(REMOTE_SOURCE_PATH_PREFIX)) {
|
|
22
|
+
const source = decodeURIComponent(sourceUrl.pathname.slice(REMOTE_SOURCE_PATH_PREFIX.length)).replace(/^\[projectRoot(?:\^\d+)?\][\\/]/, '');
|
|
23
|
+
return `${getRemoteName(inputFile) ?? sourceUrl.host}/${source}`;
|
|
24
|
+
}
|
|
25
|
+
return file.replace(/^\[projectRoot(?:\^\d+)?\][\\/]/, '');
|
|
26
|
+
}
|
|
27
|
+
export function logSymbolicatedStackFrame(logger, inputStack, results) {
|
|
28
|
+
if (!isRuntimeErrorStack(inputStack)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const frameIndex = results.stack.findIndex((stackFrame) => !isGeneratedBundleFrame(stackFrame));
|
|
32
|
+
const frame = results.stack[frameIndex];
|
|
33
|
+
if (!frame?.file || frame.lineNumber == null) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const inputFrames = inputStack.filter(isSymbolicatableFrame);
|
|
37
|
+
const file = getPrintableFile(frame.file, inputFrames[frameIndex]?.file);
|
|
38
|
+
logger.info({
|
|
39
|
+
msg: `Symbolicated stack frame: ${file}:${frame.lineNumber}:${frame.column ?? 0}`,
|
|
40
|
+
methodName: frame.methodName,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fastifyPlugin from 'fastify-plugin';
|
|
2
|
+
import { logSymbolicatedStackFrame } from './logSymbolicatedStackFrame.js';
|
|
2
3
|
import { Symbolicator } from './Symbolicator.js';
|
|
3
4
|
function getStackFromRequestBody(request) {
|
|
4
5
|
let body;
|
|
@@ -25,6 +26,7 @@ async function symbolicatePlugin(instance, { delegate, }) {
|
|
|
25
26
|
else {
|
|
26
27
|
request.log.debug({ msg: 'Starting symbolication', platform, stack });
|
|
27
28
|
const results = await symbolicator.process(request.log, stack);
|
|
29
|
+
logSymbolicatedStackFrame(request.log, stack, results);
|
|
28
30
|
reply.send(results);
|
|
29
31
|
}
|
|
30
32
|
}
|
|
@@ -17,7 +17,7 @@ export declare abstract class WebSocketServer<T extends WebSocket = WebSocket> i
|
|
|
17
17
|
protected paths: string[];
|
|
18
18
|
protected clients: Map<string, T>;
|
|
19
19
|
protected nextClientId: number;
|
|
20
|
-
private
|
|
20
|
+
private heartbeatTimer;
|
|
21
21
|
/**
|
|
22
22
|
* Create a new instance of the WebSocketServer.
|
|
23
23
|
* Any logging information, will be passed through standard `fastify.log` API.
|
|
@@ -15,7 +15,6 @@ export class WebSocketServer {
|
|
|
15
15
|
*/
|
|
16
16
|
constructor(fastify, options) {
|
|
17
17
|
this.nextClientId = 0;
|
|
18
|
-
this.timer = null;
|
|
19
18
|
this.fastify = fastify;
|
|
20
19
|
this.name = options.name;
|
|
21
20
|
this.paths = Array.isArray(options.path) ? options.path : [options.path];
|
|
@@ -23,7 +22,7 @@ export class WebSocketServer {
|
|
|
23
22
|
this.server.on('connection', this.onConnection.bind(this));
|
|
24
23
|
this.clients = new Map();
|
|
25
24
|
// setup heartbeat timer
|
|
26
|
-
this.
|
|
25
|
+
this.heartbeatTimer = setInterval(() => {
|
|
27
26
|
this.clients.forEach((socket) => {
|
|
28
27
|
if (!socket.isAlive) {
|
|
29
28
|
socket.terminate();
|
|
@@ -34,6 +33,9 @@ export class WebSocketServer {
|
|
|
34
33
|
}
|
|
35
34
|
});
|
|
36
35
|
}, 30000);
|
|
36
|
+
this.fastify.addHook('onClose', async () => {
|
|
37
|
+
clearInterval(this.heartbeatTimer);
|
|
38
|
+
});
|
|
37
39
|
}
|
|
38
40
|
shouldUpgrade(pathname) {
|
|
39
41
|
return this.paths.includes(pathname);
|
|
@@ -271,7 +271,7 @@ export class WebSocketMessageServer extends WebSocketServer {
|
|
|
271
271
|
this.upgradeRequests[clientId] = request;
|
|
272
272
|
socket.addEventListener('message', (event) => {
|
|
273
273
|
const message = this.parseMessage(event.data.toString(),
|
|
274
|
-
// @ts-
|
|
274
|
+
// @ts-expect-error
|
|
275
275
|
event.binary);
|
|
276
276
|
if (!message) {
|
|
277
277
|
this.fastify.log.error({
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
2
|
import type { WebSocketServer } from 'ws';
|
|
3
3
|
import type { Server } from '../../types.js';
|
|
4
|
-
import { WebSocketRouter } from './WebSocketRouter.js';
|
|
5
|
-
import { WebSocketServerAdapter } from './WebSocketServerAdapter.js';
|
|
6
4
|
import { WebSocketApiServer } from './servers/WebSocketApiServer.js';
|
|
7
5
|
import { WebSocketDevClientServer } from './servers/WebSocketDevClientServer.js';
|
|
8
6
|
import { WebSocketEventsServer } from './servers/WebSocketEventsServer.js';
|
|
9
7
|
import { WebSocketHMRServer } from './servers/WebSocketHMRServer.js';
|
|
10
8
|
import { WebSocketMessageServer } from './servers/WebSocketMessageServer.js';
|
|
9
|
+
import { WebSocketRouter } from './WebSocketRouter.js';
|
|
10
|
+
import { WebSocketServerAdapter } from './WebSocketServerAdapter.js';
|
|
11
11
|
declare module 'fastify' {
|
|
12
12
|
interface FastifyInstance {
|
|
13
13
|
wss: {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fastifyPlugin from 'fastify-plugin';
|
|
2
|
-
import { WebSocketRouter } from './WebSocketRouter.js';
|
|
3
|
-
import { WebSocketServerAdapter } from './WebSocketServerAdapter.js';
|
|
4
2
|
import { WebSocketApiServer } from './servers/WebSocketApiServer.js';
|
|
5
3
|
import { WebSocketDevClientServer } from './servers/WebSocketDevClientServer.js';
|
|
6
4
|
import { WebSocketEventsServer } from './servers/WebSocketEventsServer.js';
|
|
7
5
|
import { WebSocketHMRServer } from './servers/WebSocketHMRServer.js';
|
|
8
6
|
import { WebSocketMessageServer } from './servers/WebSocketMessageServer.js';
|
|
7
|
+
import { WebSocketRouter } from './WebSocketRouter.js';
|
|
8
|
+
import { WebSocketServerAdapter } from './WebSocketServerAdapter.js';
|
|
9
9
|
/**
|
|
10
10
|
* Defined in @react-native/dev-middleware
|
|
11
11
|
* Reference: https://github.com/facebook/react-native/blob/main/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js
|
package/dist/types.d.ts
CHANGED
|
@@ -13,8 +13,7 @@ type MiddlewareObject<RequestInternal extends Http.IncomingMessage = Http.Incomi
|
|
|
13
13
|
middleware: MiddlewareHandler<RequestInternal, ResponseInternal>;
|
|
14
14
|
};
|
|
15
15
|
export type Middleware<RequestInternal extends Http.IncomingMessage = Http.IncomingMessage, ResponseInternal extends Http.ServerResponse = Http.ServerResponse> = MiddlewareObject<RequestInternal, ResponseInternal> | MiddlewareHandler<RequestInternal, ResponseInternal>;
|
|
16
|
-
export type { CompilerDelegate };
|
|
17
|
-
export type { CodeFrame, InputStackFrame, ReactNativeStackFrame, StackFrame, SymbolicatorDelegate, SymbolicatorResults, };
|
|
16
|
+
export type { CodeFrame, CompilerDelegate, InputStackFrame, ReactNativeStackFrame, StackFrame, SymbolicatorDelegate, SymbolicatorResults, };
|
|
18
17
|
interface ProxyConfig extends ProxyOptions {
|
|
19
18
|
path?: ProxyOptions['pathFilter'];
|
|
20
19
|
context?: ProxyOptions['pathFilter'];
|
|
@@ -128,6 +127,12 @@ export declare namespace Server {
|
|
|
128
127
|
* @returns The resolved project path.
|
|
129
128
|
*/
|
|
130
129
|
resolveProjectPath: (filepath: string) => string;
|
|
130
|
+
/**
|
|
131
|
+
* Open a stack frame owned by another development server.
|
|
132
|
+
*
|
|
133
|
+
* @returns Whether the frame was handled remotely.
|
|
134
|
+
*/
|
|
135
|
+
openStackFrame?: (filepath: string, lineNumber: number) => boolean | Promise<boolean>;
|
|
131
136
|
}
|
|
132
137
|
/**
|
|
133
138
|
* Delegate with implementation for messages used in route handlers.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RawIndexMap, RawSourceMap } from 'source-map';
|
|
2
|
+
interface StackFrameLike {
|
|
3
|
+
file: string | null;
|
|
4
|
+
}
|
|
5
|
+
export declare function normalizeInvalidWebpackSourceUrls(rawSourceMap: string | Buffer): string | RawSourceMap | RawIndexMap;
|
|
6
|
+
export declare function isGeneratedBundleFrame(frame: StackFrameLike): boolean;
|
|
7
|
+
export declare function isSymbolicatableFrame<T extends StackFrameLike>(frame: T): frame is T & {
|
|
8
|
+
file: string;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
2
|
+
export function normalizeInvalidWebpackSourceUrls(rawSourceMap) {
|
|
3
|
+
const sourceMapText = rawSourceMap.toString();
|
|
4
|
+
if (!sourceMapText.includes('webpack://')) {
|
|
5
|
+
return sourceMapText;
|
|
6
|
+
}
|
|
7
|
+
const sourceMap = JSON.parse(sourceMapText);
|
|
8
|
+
let invalidSourceIndex = 0;
|
|
9
|
+
const normalize = (map) => {
|
|
10
|
+
if (!map || typeof map !== 'object') {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const current = map;
|
|
14
|
+
if (Array.isArray(current.sources)) {
|
|
15
|
+
current.sources = current.sources.map((source) => {
|
|
16
|
+
if (typeof source !== 'string') {
|
|
17
|
+
return source;
|
|
18
|
+
}
|
|
19
|
+
const normalizedSource = source.replace(/^webpack:\/\/([^/|]+)\|\/?/, 'webpack://$1/');
|
|
20
|
+
if (!normalizedSource.startsWith('webpack://')) {
|
|
21
|
+
return normalizedSource;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
new URL(normalizedSource);
|
|
25
|
+
return normalizedSource;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Some generated Module Federation runtime modules use their source
|
|
29
|
+
// text as a webpack URL. A single invalid URL makes source-map reject
|
|
30
|
+
// the complete map, including otherwise valid application sources.
|
|
31
|
+
return `webpack://invalid-source/${invalidSourceIndex++}`;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
for (const section of current.sections ?? []) {
|
|
36
|
+
normalize(section.map);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
normalize(sourceMap);
|
|
40
|
+
// SourceMapConsumer accepts parsed maps. Returning the object avoids
|
|
41
|
+
// serializing it here only for the consumer to parse it again.
|
|
42
|
+
return sourceMap;
|
|
43
|
+
}
|
|
44
|
+
export function isGeneratedBundleFrame(frame) {
|
|
45
|
+
return Boolean(frame.file &&
|
|
46
|
+
(frame.file.includes('.bundle') || frame.file.includes('.hot-update.js')));
|
|
47
|
+
}
|
|
48
|
+
export function isSymbolicatableFrame(frame) {
|
|
49
|
+
return Boolean(frame.file &&
|
|
50
|
+
(frame.file.startsWith('http') || isGeneratedBundleFrame(frame)));
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@callstack/repack-dev-server",
|
|
3
3
|
"description": "A bundler-agnostic development server for React Native applications as part of @callstack/repack.",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.4.0-canary-20260831210904",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@types/babel__code-frame": "^7.0.6",
|
|
54
54
|
"@types/node": "^20.19.31",
|
|
55
55
|
"@types/ws": "^8.18.0",
|
|
56
|
-
"typescript": "^
|
|
56
|
+
"typescript": "^7.0.2",
|
|
57
57
|
"vitest": "^4.1.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|