@callstack/repack-dev-server 6.0.0-canary-20250430092041 → 6.0.0-canary-20250729145326

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.
@@ -1,7 +1,7 @@
1
1
  import { Writable } from 'node:stream';
2
+ import util from 'node:util';
2
3
  import middie from '@fastify/middie';
3
4
  import fastifySensible from '@fastify/sensible';
4
- import { createDevMiddleware } from '@react-native/dev-middleware';
5
5
  import Fastify from 'fastify';
6
6
  import { createProxyMiddleware } from 'http-proxy-middleware';
7
7
  import apiPlugin from './plugins/api/apiPlugin.js';
@@ -62,25 +62,51 @@ export async function createServer(config) {
62
62
  },
63
63
  });
64
64
  let handledDevMiddlewareNotice = false;
65
- const devMiddleware = createDevMiddleware({
65
+ const devMiddleware = options.devMiddleware.createDevMiddleware({
66
66
  projectRoot: options.rootDir,
67
67
  serverBaseUrl: options.url,
68
68
  logger: {
69
- error: instance.log.error,
70
- warn: instance.log.warn,
71
- info: (...message) => {
72
- if (!handledDevMiddlewareNotice) {
73
- if (message.join().includes('JavaScript logs have moved!')) {
74
- handledDevMiddlewareNotice = true;
69
+ error: (...msg) => {
70
+ const message = util.format(...msg);
71
+ instance.log.error(message);
72
+ },
73
+ warn: (...msg) => {
74
+ const message = util.format(...msg);
75
+ instance.log.warn(message);
76
+ },
77
+ info: (...msg) => {
78
+ const message = util.format(...msg);
79
+ try {
80
+ if (!handledDevMiddlewareNotice) {
81
+ if (message.includes('JavaScript logs have moved!')) {
82
+ handledDevMiddlewareNotice = true;
83
+ return;
84
+ }
85
+ }
86
+ else {
87
+ instance.log.debug(message);
75
88
  return;
76
89
  }
77
90
  }
78
- else {
79
- instance.log.info(message);
80
- return;
91
+ catch (e) {
92
+ console.log(e);
81
93
  }
82
94
  },
83
95
  },
96
+ // we need to let `Network.loadNetworkResource` event pass
97
+ // through the InspectorProxy interceptor, otherwise it will
98
+ // prevent fetching source maps over the network for MF2 remotes
99
+ unstable_customInspectorMessageHandler: (connection) => {
100
+ return {
101
+ handleDeviceMessage: () => { },
102
+ handleDebuggerMessage: (msg) => {
103
+ if (msg.method === 'Network.loadNetworkResource') {
104
+ connection.device.sendMessage(msg);
105
+ return true;
106
+ }
107
+ },
108
+ };
109
+ },
84
110
  unstable_experiments: {
85
111
  // @ts-expect-error removed in 0.76, keep this for backkwards compatibility
86
112
  enableNewDebugger: true,
@@ -105,7 +131,7 @@ export async function createServer(config) {
105
131
  delegate,
106
132
  });
107
133
  await instance.register(devtoolsPlugin, {
108
- rootDir: options.rootDir,
134
+ delegate,
109
135
  });
110
136
  await instance.register(symbolicatePlugin, {
111
137
  delegate,
@@ -122,11 +148,32 @@ export async function createServer(config) {
122
148
  }
123
149
  return payload;
124
150
  });
125
- // Register dev middleware
126
- instance.use(devMiddleware.middleware);
127
- // Register proxy middlewares
128
- proxyMiddlewares?.forEach((proxyMiddleware) => {
129
- instance.use(proxyMiddleware);
151
+ // Setup middlewares
152
+ // Expose built-in middlewares to setupMiddlewares
153
+ const builtInMiddlewares = [
154
+ {
155
+ name: 'dev-middleware',
156
+ middleware: devMiddleware.middleware,
157
+ },
158
+ ...(proxyMiddlewares?.map((proxyMiddleware, index) => ({
159
+ name: `proxy-middleware-${index}`,
160
+ middleware: proxyMiddleware,
161
+ })) ?? []),
162
+ ];
163
+ const finalMiddlewares = options.setupMiddlewares(builtInMiddlewares, instance);
164
+ // Register middlewares
165
+ finalMiddlewares.forEach((middleware) => {
166
+ if (typeof middleware === 'object') {
167
+ if (middleware.path !== undefined) {
168
+ instance.use(middleware.path, middleware.middleware);
169
+ }
170
+ else {
171
+ instance.use(middleware.middleware);
172
+ }
173
+ }
174
+ else {
175
+ instance.use(middleware);
176
+ }
130
177
  });
131
178
  // Register routes
132
179
  instance.get('/', async () => delegate.messages.getHello());
@@ -14,9 +14,9 @@ async function compilerPlugin(instance, { delegate }) {
14
14
  },
15
15
  },
16
16
  handler: async (request, reply) => {
17
- const filename = request.params['*'];
17
+ const filepath = request.params['*'];
18
18
  let { platform } = request.query;
19
- if (!filename) {
19
+ if (!filepath) {
20
20
  // This technically should never happen - this route should not be called if file is missing.
21
21
  request.log.debug('File was not provided');
22
22
  return reply.notFound('File was not provided');
@@ -33,8 +33,8 @@ async function compilerPlugin(instance, { delegate }) {
33
33
  }));
34
34
  };
35
35
  try {
36
- const asset = await delegate.compiler.getAsset(filename, platform, sendProgress);
37
- const mimeType = delegate.compiler.getMimeType(filename, platform, asset);
36
+ const asset = await delegate.compiler.getAsset(filepath, platform, sendProgress);
37
+ const mimeType = delegate.compiler.getMimeType(filepath, platform, asset);
38
38
  if (multipart) {
39
39
  const buffer = Buffer.isBuffer(asset) ? asset : Buffer.from(asset);
40
40
  multipart.setHeader('Content-Type', `${mimeType}; charset=UTF-8`);
@@ -1,4 +1,7 @@
1
1
  import type { FastifyInstance } from 'fastify';
2
- declare function devtoolsPlugin(instance: FastifyInstance): Promise<void>;
2
+ import type { Server } from '../../types.js';
3
+ declare function devtoolsPlugin(instance: FastifyInstance, { delegate }: {
4
+ delegate: Server.Delegate;
5
+ }): Promise<void>;
3
6
  declare const _default: typeof devtoolsPlugin;
4
7
  export default _default;
@@ -8,7 +8,7 @@ function parseRequestBody(body) {
8
8
  return JSON.parse(body);
9
9
  throw new Error(`Unsupported body type: ${typeof body}`);
10
10
  }
11
- async function devtoolsPlugin(instance) {
11
+ async function devtoolsPlugin(instance, { delegate }) {
12
12
  // reference implementation in `@react-native-community/cli-server-api`:
13
13
  // https://github.com/react-native-community/cli/blob/46436a12478464752999d34ed86adf3212348007/packages/cli-server-api/src/openURLMiddleware.ts
14
14
  instance.route({
@@ -27,8 +27,8 @@ async function devtoolsPlugin(instance) {
27
27
  url: '/open-stack-frame',
28
28
  handler: async (request, reply) => {
29
29
  const { file, lineNumber } = parseRequestBody(request.body);
30
- // TODO fix rewriting of `webpack://` to rootDir of the project
31
- launchEditor(`${file}:${lineNumber}`, process.env.REACT_EDITOR);
30
+ const filepath = delegate.devTools?.resolveProjectPath(file) ?? file;
31
+ launchEditor(`${filepath}:${lineNumber}`, process.env.REACT_EDITOR);
32
32
  reply.send('OK');
33
33
  },
34
34
  });
@@ -131,16 +131,21 @@ export class Symbolicator {
131
131
  collapse: false,
132
132
  };
133
133
  }
134
- const lookup = consumer.originalPositionFor({
134
+ let lookup = consumer.originalPositionFor({
135
135
  line: frame.lineNumber,
136
136
  column: frame.column,
137
137
  bias: SourceMapConsumer.LEAST_UPPER_BOUND,
138
138
  });
139
- // If lookup fails, we get the same shape object, but with
140
- // all values set to null
141
139
  if (!lookup.source) {
142
- // It is better to gracefully return the original frame
143
- // than to throw an exception
140
+ // fallback to GREATEST_LOWER_BOUND
141
+ lookup = consumer.originalPositionFor({
142
+ line: frame.lineNumber,
143
+ column: frame.column,
144
+ bias: SourceMapConsumer.GREATEST_LOWER_BOUND,
145
+ });
146
+ }
147
+ // return the original frame when both lookups fail
148
+ if (!lookup.source) {
144
149
  return {
145
150
  ...frame,
146
151
  collapse: false,
package/dist/types.d.ts CHANGED
@@ -1,15 +1,25 @@
1
- import type { ServerOptions as HttpsServerOptions } from 'node:https';
2
- import type { FastifyBaseLogger } from 'fastify';
1
+ import type * as Http from 'node:http';
2
+ import type * as Https from 'node:https';
3
+ import type * as DevMiddleware from '@react-native/dev-middleware';
4
+ import type { FastifyBaseLogger, FastifyInstance } from 'fastify';
3
5
  import type { Options as ProxyOptions } from 'http-proxy-middleware';
4
6
  import type { CompilerDelegate } from './plugins/compiler/types.js';
5
7
  import type { CodeFrame, InputStackFrame, ReactNativeStackFrame, StackFrame, SymbolicatorDelegate, SymbolicatorResults } from './plugins/symbolicate/types.js';
6
8
  import type { NormalizedOptions } from './utils/normalizeOptions.js';
9
+ type MiddlewareHandler<RequestInternal extends Http.IncomingMessage = Http.IncomingMessage, ResponseInternal extends Http.ServerResponse = Http.ServerResponse> = (req: RequestInternal, res: ResponseInternal, next: (err?: any) => void) => void | Promise<void>;
10
+ type MiddlewareObject<RequestInternal extends Http.IncomingMessage = Http.IncomingMessage, ResponseInternal extends Http.ServerResponse = Http.ServerResponse> = {
11
+ name?: string;
12
+ path?: string;
13
+ middleware: MiddlewareHandler<RequestInternal, ResponseInternal>;
14
+ };
15
+ export type Middleware<RequestInternal extends Http.IncomingMessage = Http.IncomingMessage, ResponseInternal extends Http.ServerResponse = Http.ServerResponse> = MiddlewareObject<RequestInternal, ResponseInternal> | MiddlewareHandler<RequestInternal, ResponseInternal>;
7
16
  export type { CompilerDelegate };
8
17
  export type { CodeFrame, InputStackFrame, ReactNativeStackFrame, StackFrame, SymbolicatorDelegate, SymbolicatorResults, };
9
18
  interface ProxyConfig extends ProxyOptions {
10
19
  path?: ProxyOptions['pathFilter'];
11
20
  context?: ProxyOptions['pathFilter'];
12
21
  }
22
+ export type SetupMiddlewaresFunction = (middlewares: Middleware[], devServer: FastifyInstance) => Middleware[];
13
23
  export interface DevServerOptions {
14
24
  /**
15
25
  * Hostname or IP address under which to run the development server.
@@ -27,8 +37,10 @@ export interface DevServerOptions {
27
37
  type: 'http';
28
38
  } | {
29
39
  type: 'https';
30
- options?: HttpsServerOptions;
40
+ options?: Https.ServerOptions;
31
41
  };
42
+ /** Function to customize middleware setup. Receives built-in middlewares and Fastify instance. */
43
+ setupMiddlewares?: SetupMiddlewaresFunction;
32
44
  }
33
45
  export declare namespace Server {
34
46
  /** Development server configuration. */
@@ -44,6 +56,8 @@ export declare namespace Server {
44
56
  rootDir: string;
45
57
  /** Whether to enable logging requests. */
46
58
  logRequests?: boolean;
59
+ /** `@react-native/dev-middleware` module. */
60
+ devMiddleware: typeof DevMiddleware;
47
61
  }
48
62
  /**
49
63
  * A complete delegate with implementations for all server functionalities.
@@ -51,6 +65,8 @@ export declare namespace Server {
51
65
  interface Delegate {
52
66
  /** A compiler delegate. */
53
67
  compiler: CompilerDelegate;
68
+ /** A DevTools delegate. */
69
+ devTools?: DevToolsDelegate;
54
70
  /** A symbolicator delegate. */
55
71
  symbolicator: SymbolicatorDelegate;
56
72
  /** A logger delegate. */
@@ -101,6 +117,18 @@ export declare namespace Server {
101
117
  */
102
118
  onMessage: (log: any) => void;
103
119
  }
120
+ /**
121
+ * Delegate with implementation for dev tools functions.
122
+ */
123
+ interface DevToolsDelegate {
124
+ /**
125
+ * Resolve the project filepath with [projectRoot] prefix.
126
+ *
127
+ * @param filepath The filepath to resolve.
128
+ * @returns The resolved project path.
129
+ */
130
+ resolveProjectPath: (filepath: string) => string;
131
+ }
104
132
  /**
105
133
  * Delegate with implementation for messages used in route handlers.
106
134
  */
@@ -1,6 +1,7 @@
1
1
  import type { ServerOptions as HttpsServerOptions } from 'node:https';
2
+ import type * as DevMiddleware from '@react-native/dev-middleware';
2
3
  import type { Options as ProxyOptions } from 'http-proxy-middleware';
3
- import type { Server } from '../types.js';
4
+ import type { Server, SetupMiddlewaresFunction } from '../types.js';
4
5
  export interface NormalizedOptions {
5
6
  host: string;
6
7
  port: number;
@@ -9,6 +10,8 @@ export interface NormalizedOptions {
9
10
  proxy: ProxyOptions[] | undefined;
10
11
  url: string;
11
12
  disableRequestLogging: boolean;
13
+ devMiddleware: typeof DevMiddleware;
12
14
  rootDir: string;
15
+ setupMiddlewares: SetupMiddlewaresFunction;
13
16
  }
14
17
  export declare function normalizeOptions(options: Server.Options): NormalizedOptions;
@@ -21,6 +21,10 @@ function normalizeProxyOptions(proxyOptions, fallbackTarget) {
21
21
  }
22
22
  return undefined;
23
23
  }
24
+ function normalizeSetupMiddlewares(setupMiddlewares) {
25
+ // create a passthrough function if no setupMiddlewares is provided
26
+ return setupMiddlewares ?? ((middlewares) => middlewares);
27
+ }
24
28
  export function normalizeOptions(options) {
25
29
  const host = options.host ?? 'localhost';
26
30
  const port = options.port ?? 8081;
@@ -29,6 +33,7 @@ export function normalizeOptions(options) {
29
33
  const protocol = https ? 'https' : 'http';
30
34
  const url = `${protocol}://${host}:${options.port}`;
31
35
  const proxy = normalizeProxyOptions(options.proxy, url);
36
+ const setupMiddlewares = normalizeSetupMiddlewares(options.setupMiddlewares);
32
37
  return {
33
38
  // webpack dev server compatible options
34
39
  host,
@@ -37,9 +42,13 @@ export function normalizeOptions(options) {
37
42
  hot,
38
43
  proxy,
39
44
  url,
45
+ // dev middleware
46
+ devMiddleware: options.devMiddleware,
40
47
  // fastify options
41
48
  disableRequestLogging: !options.logRequests,
42
49
  // project options
43
50
  rootDir: options.rootDir,
51
+ // custom middleware setup
52
+ setupMiddlewares,
44
53
  };
45
54
  }
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": "6.0.0-canary-20250430092041",
5
+ "version": "6.0.0-canary-20250729145326",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
@@ -35,7 +35,6 @@
35
35
  "@babel/code-frame": "^7.26.2",
36
36
  "@fastify/middie": "^8.3.0",
37
37
  "@fastify/sensible": "^5.5.0",
38
- "@react-native/dev-middleware": "^0.78.0",
39
38
  "fastify": "^4.24.3",
40
39
  "fastify-favicon": "^4.3.0",
41
40
  "fastify-plugin": "^4.5.1",
@@ -47,8 +46,9 @@
47
46
  "ws": "^8.18.1"
48
47
  },
49
48
  "devDependencies": {
49
+ "@react-native/dev-middleware": "^0.80.0",
50
50
  "@types/babel__code-frame": "^7.0.6",
51
- "@types/node": "^18",
51
+ "@types/node": "^20",
52
52
  "@types/ws": "^8.18.0",
53
53
  "typescript": "^5.8.3"
54
54
  },
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};