rollipop 1.0.0-alpha.21 → 1.0.0-alpha.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/{chunk-DEq-mXcV.js → _virtual/_rolldown/runtime.js} +1 -1
  3. package/dist/commands.d.ts +2 -4
  4. package/dist/commands.js +10 -3957
  5. package/dist/common/code.js +21 -0
  6. package/dist/common/constants.js +5 -0
  7. package/dist/common/env.js +33 -0
  8. package/dist/common/logger.d.ts +34 -0
  9. package/dist/common/logger.js +82 -0
  10. package/dist/common/logo.js +54 -0
  11. package/dist/common/progress-bar.js +167 -0
  12. package/dist/common/transformer.js +13 -0
  13. package/dist/common/types.d.ts +10 -0
  14. package/dist/config/compose-override.js +18 -0
  15. package/dist/config/defaults.d.ts +74 -0
  16. package/dist/config/defaults.js +74 -0
  17. package/dist/config/define-config.d.ts +13 -0
  18. package/dist/config/define-config.js +6 -0
  19. package/dist/config/index.d.ts +5 -0
  20. package/dist/config/index.js +5 -0
  21. package/dist/config/load-config.d.ts +19 -0
  22. package/dist/config/load-config.js +73 -0
  23. package/dist/config/merge-config.d.ts +12 -0
  24. package/dist/config/merge-config.js +20 -0
  25. package/dist/config/types.d.ts +452 -0
  26. package/dist/constants.d.ts +35 -0
  27. package/dist/constants.js +146 -0
  28. package/dist/core/assets.d.ts +91 -0
  29. package/dist/core/assets.js +244 -0
  30. package/dist/core/bundler.d.ts +15 -0
  31. package/dist/core/bundler.js +80 -0
  32. package/dist/core/env.d.ts +11 -0
  33. package/dist/core/env.js +36 -0
  34. package/dist/core/fs/data.js +9 -0
  35. package/dist/core/fs/storage.d.ts +15 -0
  36. package/dist/core/fs/storage.js +31 -0
  37. package/dist/core/plugins/babel-plugin.d.ts +22 -0
  38. package/dist/core/plugins/babel-plugin.js +74 -0
  39. package/dist/core/plugins/context.d.ts +10 -0
  40. package/dist/core/plugins/context.js +24 -0
  41. package/dist/core/plugins/dev-server-plugin.d.ts +13 -0
  42. package/dist/core/plugins/dev-server-plugin.js +27 -0
  43. package/dist/core/plugins/index.d.ts +13 -0
  44. package/dist/core/plugins/index.js +18 -0
  45. package/dist/core/plugins/prelude-plugin.d.ts +10 -0
  46. package/dist/core/plugins/prelude-plugin.js +23 -0
  47. package/dist/core/plugins/react-native-plugin.d.ts +36 -0
  48. package/dist/core/plugins/react-native-plugin.js +81 -0
  49. package/dist/core/plugins/reporter-plugin.d.ts +11 -0
  50. package/dist/core/plugins/reporter-plugin.js +87 -0
  51. package/dist/core/plugins/shared/filters.js +5 -0
  52. package/dist/core/plugins/swc-plugin.d.ts +26 -0
  53. package/dist/core/plugins/swc-plugin.js +108 -0
  54. package/dist/core/plugins/types.d.ts +18 -0
  55. package/dist/core/plugins/utils/source.js +10 -0
  56. package/dist/core/plugins/utils/transform-utils.js +56 -0
  57. package/dist/core/rolldown.js +313 -0
  58. package/dist/core/settings.js +19 -0
  59. package/dist/core/types.d.ts +83 -0
  60. package/dist/filter.d.ts +1 -0
  61. package/dist/filter.js +2 -0
  62. package/dist/hmr-runtime.iife.js +5 -5
  63. package/dist/index.d.ts +24 -1221
  64. package/dist/index.js +19 -4029
  65. package/dist/internal/react-native.js +24 -0
  66. package/dist/logger.js +5 -0
  67. package/dist/node/cli-utils.d.ts +10 -0
  68. package/dist/node/cli-utils.js +28 -0
  69. package/dist/node/cli.d.ts +6 -0
  70. package/dist/node/cli.js +23 -0
  71. package/dist/node/commands/agent/action.js +91 -0
  72. package/dist/node/commands/agent/command.js +10 -0
  73. package/dist/node/commands/agent/index.js +2 -0
  74. package/dist/node/commands/bundle/action.js +33 -0
  75. package/dist/node/commands/bundle/command.js +96 -0
  76. package/dist/node/commands/bundle/index.js +2 -0
  77. package/dist/node/commands/start/action.js +37 -0
  78. package/dist/node/commands/start/command.js +93 -0
  79. package/dist/node/commands/start/debugger.js +79 -0
  80. package/dist/node/commands/start/index.js +2 -0
  81. package/dist/node/commands/start/setup-interactive-mode.d.ts +20 -0
  82. package/dist/node/commands/start/setup-interactive-mode.js +107 -0
  83. package/dist/node/constants.js +4 -0
  84. package/dist/node/logger.js +5 -0
  85. package/dist/node/types.d.ts +23 -0
  86. package/dist/node/utils.js +23 -0
  87. package/dist/package.js +4 -0
  88. package/dist/runtime.js +1 -1
  89. package/dist/server/bundle.d.ts +12 -0
  90. package/dist/server/bundle.js +55 -0
  91. package/dist/server/bundler-pool.d.ts +51 -0
  92. package/dist/server/bundler-pool.js +197 -0
  93. package/dist/server/common/schema.js +19 -0
  94. package/dist/server/constants.d.ts +6 -0
  95. package/dist/server/constants.js +6 -0
  96. package/dist/server/create-dev-server.d.ts +6 -0
  97. package/dist/server/create-dev-server.js +185 -0
  98. package/dist/server/error.js +9 -0
  99. package/dist/server/events/event-bus.d.ts +12 -0
  100. package/dist/server/events/event-bus.js +16 -0
  101. package/dist/server/events/types.d.ts +37 -0
  102. package/dist/server/events/types.js +6 -0
  103. package/dist/server/index.d.ts +3 -0
  104. package/dist/server/index.js +3 -0
  105. package/dist/server/logger.js +33 -0
  106. package/dist/server/mcp/context.js +14 -0
  107. package/dist/server/mcp/server.js +86 -0
  108. package/dist/server/mcp/tools/app-log-diagnostics.js +37 -0
  109. package/dist/server/mcp/tools/build-diagnostics.js +97 -0
  110. package/dist/server/mcp/tools/build-info.js +33 -0
  111. package/dist/server/mcp/tools/device-diagnostics.js +52 -0
  112. package/dist/server/mcp/tools/index.js +277 -0
  113. package/dist/server/middlewares/request-logger.js +15 -0
  114. package/dist/server/middlewares/serve-assets.js +49 -0
  115. package/dist/server/middlewares/serve-bundle.js +72 -0
  116. package/dist/server/middlewares/sse.js +34 -0
  117. package/dist/server/middlewares/symbolicate.js +71 -0
  118. package/dist/server/sse/adapter.js +74 -0
  119. package/dist/server/sse/event-bus.js +26 -0
  120. package/dist/server/symbolicate.js +93 -0
  121. package/dist/server/types.d.ts +125 -0
  122. package/dist/server/wss/hmr-server.js +209 -0
  123. package/dist/server/wss/server.d.ts +9 -0
  124. package/dist/server/wss/server.js +70 -0
  125. package/dist/{runtime.d.cts → types/hmr.d.ts} +1 -12
  126. package/dist/types.d.ts +78 -0
  127. package/dist/utils/babel.js +11 -0
  128. package/dist/utils/build-options.js +17 -0
  129. package/dist/utils/bundle.js +6 -0
  130. package/dist/utils/config.d.ts +5 -0
  131. package/dist/utils/config.js +32 -0
  132. package/dist/utils/dev-server.js +51 -0
  133. package/dist/utils/env.js +7 -0
  134. package/dist/utils/errors.js +9 -0
  135. package/dist/utils/hash.js +8 -0
  136. package/dist/utils/id.js +28 -0
  137. package/dist/utils/node-resolve.js +42 -0
  138. package/dist/utils/promise.js +15 -0
  139. package/dist/utils/reporters.js +120 -0
  140. package/dist/utils/reset-cache.d.ts +8 -0
  141. package/dist/utils/reset-cache.js +25 -0
  142. package/dist/utils/response.js +91 -0
  143. package/dist/utils/run-build.d.ts +8 -0
  144. package/dist/utils/run-build.js +7 -0
  145. package/dist/utils/run-server.d.ts +6 -0
  146. package/dist/utils/run-server.js +20 -0
  147. package/dist/utils/runtime-target.js +9 -0
  148. package/dist/utils/serialize.js +10 -0
  149. package/dist/utils/server.js +6 -0
  150. package/dist/utils/storage.js +6 -0
  151. package/dist/utils/string.js +6 -0
  152. package/dist/utils/swc.js +10 -0
  153. package/dist/utils/terminal.js +86 -0
  154. package/dist/utils/url.js +23 -0
  155. package/package.json +56 -68
  156. package/dist/commands.cjs +0 -4008
  157. package/dist/commands.d.cts +0 -5
  158. package/dist/pluginutils.d.ts +0 -1
  159. package/dist/pluginutils.js +0 -2
  160. package/dist/runtime.cjs +0 -34
  161. /package/dist/{chunk-DXpK5_cz.js → chunk-DJV587Yu.js} +0 -0
@@ -0,0 +1,93 @@
1
+ import { parseUrl } from "../utils/url.js";
2
+ import { codeFrameColumns } from "@babel/code-frame";
3
+ //#region src/server/symbolicate.ts
4
+ /**
5
+ * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/metro-config/src/index.flow.js#L17
6
+ */
7
+ const INTERNAL_CALLSITES_REGEX = new RegExp([
8
+ "/Libraries/BatchedBridge/MessageQueue\\.js$",
9
+ "/Libraries/Core/.+\\.js$",
10
+ "/Libraries/LogBox/.+\\.js$",
11
+ "/Libraries/Network/.+\\.js$",
12
+ "/Libraries/Pressability/.+\\.js$",
13
+ "/Libraries/Renderer/implementations/.+\\.js$",
14
+ "/Libraries/Utilities/.+\\.js$",
15
+ "/Libraries/vendor/.+\\.js$",
16
+ "/Libraries/WebSocket/.+\\.js$",
17
+ "/src/private/renderer/errorhandling/.+\\.js$",
18
+ "/metro-runtime/.+\\.js$",
19
+ "/node_modules/@babel/runtime/.+\\.js$",
20
+ "/node_modules/@react-native/js-polyfills/.+\\.js$",
21
+ "/node_modules/invariant/.+\\.js$",
22
+ "/node_modules/react-devtools-core/.+\\.js$",
23
+ "/node_modules/react-native/index.js$",
24
+ "/node_modules/react-refresh/.+\\.js$",
25
+ "/node_modules/scheduler/.+\\.js$",
26
+ "^\\[native code\\]$"
27
+ ].map((pathPattern) => pathPattern.replaceAll("/", "[/\\\\]")).join("|"));
28
+ async function symbolicate(bundleStore, stack) {
29
+ const sourceMapConsumer = await bundleStore.sourceMapConsumer;
30
+ const symbolicatedStack = stack.filter((frame) => frame.file?.startsWith("http")).map((frame) => sourceMapConsumer ? originalPositionFor(sourceMapConsumer, frame) : frame).map((frame) => collapseFrame(frame));
31
+ return {
32
+ stack: symbolicatedStack,
33
+ codeFrame: getCodeFrame(symbolicatedStack, bundleStore, sourceMapConsumer)
34
+ };
35
+ }
36
+ function originalPositionFor(sourceMapConsumer, frame) {
37
+ if (frame.column == null || frame.lineNumber == null) return frame;
38
+ const originalPosition = sourceMapConsumer.originalPositionFor({
39
+ column: frame.column,
40
+ line: frame.lineNumber
41
+ });
42
+ return Object.entries(originalPosition).reduce((frame, [key, value]) => {
43
+ const targetKey = convertFrameKey(key);
44
+ return {
45
+ ...frame,
46
+ ...value ? { [targetKey]: value } : null
47
+ };
48
+ }, frame);
49
+ }
50
+ function collapseFrame(frame) {
51
+ return {
52
+ ...frame,
53
+ collapse: Boolean(frame.file && INTERNAL_CALLSITES_REGEX.test(frame.file))
54
+ };
55
+ }
56
+ function isCollapsed(frame) {
57
+ return "collapse" in frame && frame.collapse;
58
+ }
59
+ function convertFrameKey(key) {
60
+ if (key === "line") return "lineNumber";
61
+ else if (key === "source") return "file";
62
+ else if (key === "name") return "methodName";
63
+ return key;
64
+ }
65
+ function getCodeFrame(frames, bundleStore, sourceMapConsumer) {
66
+ const frame = frames.find((frame) => {
67
+ return frame.lineNumber != null && frame.column != null && !isCollapsed(frame);
68
+ });
69
+ if (frame?.file == null || frame.column == null || frame.lineNumber == null) return null;
70
+ try {
71
+ const { lineNumber, column, file } = frame;
72
+ const unresolved = file.startsWith("http");
73
+ const source = sourceMapConsumer == null || unresolved ? bundleStore.code : sourceMapConsumer.sourceContentFor(frame.file);
74
+ const fileName = unresolved ? parseUrl(file).pathname ?? "unknown" : file;
75
+ let content = "";
76
+ if (source) content = codeFrameColumns(source, { start: {
77
+ column,
78
+ line: lineNumber
79
+ } }, { highlightCode: true });
80
+ return {
81
+ content,
82
+ fileName,
83
+ location: {
84
+ column,
85
+ row: lineNumber
86
+ }
87
+ };
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+ //#endregion
93
+ export { symbolicate };
@@ -0,0 +1,125 @@
1
+ import { BuildOptions } from "../core/types.js";
2
+ import { WebSocketClient } from "./wss/server.js";
3
+ import { ServerEventBus } from "./events/event-bus.js";
4
+ import { BundlerPool } from "./bundler-pool.js";
5
+ import { ResolvedConfig } from "../config/defaults.js";
6
+ import { FastifyInstance } from "fastify";
7
+ import { Emitter } from "mitt";
8
+ import * as ws from "ws";
9
+ import * as fastifyMiddie from "@fastify/middie";
10
+
11
+ //#region src/server/types.d.ts
12
+ type FastifyInstance$1 = FastifyInstance & {
13
+ use(fn: fastifyMiddie.Handler): FastifyInstance$1;
14
+ use(route: string, fn: fastifyMiddie.Handler): FastifyInstance$1;
15
+ use(routes: string[], fn: fastifyMiddie.Handler): FastifyInstance$1;
16
+ };
17
+ interface ServerOptions {
18
+ port?: number;
19
+ host?: string;
20
+ https?: boolean;
21
+ key?: string;
22
+ cert?: string;
23
+ buildOptions?: Pick<BuildOptions, 'cache'>;
24
+ mcp?: boolean;
25
+ }
26
+ interface DevServerContext {
27
+ /**
28
+ * The base URL of the development server.
29
+ */
30
+ serverBaseUrl: string;
31
+ /**
32
+ * Resolved Rollipop config.
33
+ */
34
+ config: ResolvedConfig;
35
+ /**
36
+ * Server options.
37
+ */
38
+ options: ServerOptions;
39
+ /**
40
+ * The bundler pool.
41
+ */
42
+ bundlerPool: BundlerPool;
43
+ /**
44
+ * The event bus.
45
+ */
46
+ eventBus: ServerEventBus;
47
+ /**
48
+ * The message websocket server API.
49
+ */
50
+ message: ws.Server & {
51
+ /**
52
+ * Broadcast a message to all connected devices.
53
+ */
54
+ broadcast: (method: string, params?: Record<string, any>) => void;
55
+ };
56
+ /**
57
+ * The events websocket server API.
58
+ */
59
+ events: ws.Server & {
60
+ /**
61
+ * Report an event to the reporter.
62
+ */
63
+ reportEvent: (event: {
64
+ type: string;
65
+ [key: string]: unknown;
66
+ }) => void;
67
+ };
68
+ /**
69
+ * HMR websocket server API
70
+ */
71
+ hot: ws.Server & {
72
+ send: (client: ws.WebSocket, eventName: string, payload?: unknown) => void;
73
+ sendAll: (eventName: string, payload?: unknown) => void;
74
+ };
75
+ }
76
+ type DevServerEvents = {
77
+ 'device.connected': {
78
+ client: WebSocketClient;
79
+ };
80
+ 'device.message': {
81
+ client: WebSocketClient;
82
+ data: ws.RawData;
83
+ };
84
+ 'device.error': {
85
+ client: WebSocketClient;
86
+ error: Error;
87
+ };
88
+ 'device.disconnected': {
89
+ client: WebSocketClient;
90
+ };
91
+ };
92
+ interface Middlewares {
93
+ /**
94
+ * Register a middleware to the Fastify instance.
95
+ *
96
+ * **NOTE**: This is a wrapper of `instance.use`.
97
+ */
98
+ use: FastifyInstance$1['use'];
99
+ }
100
+ type DevServer = {
101
+ /**
102
+ * The Fastify instance.
103
+ */
104
+ instance: FastifyInstance$1;
105
+ /**
106
+ * `express` and `connect` style middleware registration API.
107
+ */
108
+ middlewares: Middlewares;
109
+ } & DevServerContext & Emitter<DevServerEvents>;
110
+ interface BundleDetails {
111
+ bundleType: string;
112
+ dev: boolean;
113
+ entryFile: string;
114
+ minify: boolean;
115
+ platform?: string;
116
+ }
117
+ interface FormattedError {
118
+ type: string;
119
+ message: string;
120
+ errors: {
121
+ description: string;
122
+ }[];
123
+ }
124
+ //#endregion
125
+ export { BundleDetails, DevServer, DevServerContext, DevServerEvents, FastifyInstance$1 as FastifyInstance, FormattedError, Middlewares, ServerOptions };
@@ -0,0 +1,209 @@
1
+ import { isBundlerEventForId } from "../events/types.js";
2
+ import { WebSocketServer } from "./server.js";
3
+ import { invariant } from "es-toolkit";
4
+ //#region src/server/wss/hmr-server.ts
5
+ var HMRServer = class extends WebSocketServer {
6
+ bundlerPool;
7
+ eventBus;
8
+ instances = /* @__PURE__ */ new Map();
9
+ bindings = /* @__PURE__ */ new Map();
10
+ constructor({ bundlerPool, eventBus }) {
11
+ super("hmr", { noServer: true });
12
+ this.bundlerPool = bundlerPool;
13
+ this.eventBus = eventBus;
14
+ }
15
+ parseClientMessage(data) {
16
+ const parsedData = JSON.parse(this.rawDataToString(data));
17
+ const clientMessage = "type" in parsedData ? parsedData : null;
18
+ invariant(clientMessage, "Invalid HMR client message");
19
+ return clientMessage;
20
+ }
21
+ async handleConnected(client, platform, bundleEntry) {
22
+ try {
23
+ this.logger.trace(`HMR client connected (clientId: ${client.id})`, {
24
+ platform,
25
+ bundleEntry
26
+ });
27
+ const devEngineInstance = this.bundlerPool.get(bundleEntry, {
28
+ platform,
29
+ dev: true
30
+ });
31
+ this.bindEvents(client, devEngineInstance);
32
+ this.instances.set(client.id, devEngineInstance);
33
+ this.logger.trace(`Bundler instance prepared (bundlerId: ${devEngineInstance.id})`);
34
+ } catch (error) {
35
+ this.logger.error(`Failed to prepare bundler instance`, error);
36
+ }
37
+ }
38
+ bindEvents(client, instance) {
39
+ if (this.bindings.get(client.id) == null) {
40
+ const unsubscribe = this.eventBus.subscribe((event) => {
41
+ if (!isBundlerEventForId(event, instance.id)) return;
42
+ switch (event.type) {
43
+ case "hmr_updates":
44
+ this.handleUpdates(client, event.updates);
45
+ break;
46
+ case "hmr_failed":
47
+ this.sendBuildFailed(client, event.error);
48
+ break;
49
+ }
50
+ });
51
+ this.bindings.set(client.id, { unsubscribe });
52
+ this.logger.trace(`HMR event binding established (clientId: ${client.id})`);
53
+ }
54
+ }
55
+ sendBuildFailed(client, error) {
56
+ this.send(client, JSON.stringify({
57
+ type: "hmr:error",
58
+ payload: {
59
+ type: "BuildError",
60
+ errors: [{ description: error.message }],
61
+ message: error.message
62
+ }
63
+ }));
64
+ }
65
+ async handleModuleRegistered(client, modules) {
66
+ try {
67
+ const instance = this.instances.get(client.id);
68
+ invariant(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
69
+ await instance.ensureInitialized;
70
+ await instance.devEngine.registerModules(client.id.toString(), modules);
71
+ } catch (error) {
72
+ this.logger.error(`Failed to handle module registered`, error);
73
+ }
74
+ }
75
+ async handleInvalidate(client, moduleId) {
76
+ try {
77
+ const instance = this.instances.get(client.id);
78
+ invariant(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
79
+ await instance.ensureInitialized;
80
+ const updates = await instance.devEngine.invalidate(moduleId);
81
+ await this.handleUpdates(client, updates);
82
+ } catch (error) {
83
+ this.logger.error(`Failed to handle invalidate`, error);
84
+ }
85
+ }
86
+ async handleUpdates(client, updates) {
87
+ this.logger.trace(`HMR updates found (clientId: ${client.id})`, { updatesCount: updates.length });
88
+ const actionableUpdates = updates.filter((clientUpdate) => clientUpdate.update.type !== "Noop");
89
+ if (actionableUpdates.length === 0) return;
90
+ this.send(client, JSON.stringify({ type: "hmr:update-start" }));
91
+ for (const clientUpdate of actionableUpdates) {
92
+ const update = clientUpdate.update;
93
+ switch (update.type) {
94
+ case "Patch":
95
+ this.sendUpdateToClient(client, update);
96
+ break;
97
+ case "FullReload":
98
+ this.sendReloadToClient(client);
99
+ break;
100
+ case "Noop": break;
101
+ }
102
+ }
103
+ }
104
+ sendUpdateToClient(client, update) {
105
+ invariant(update.type === "Patch", "Invalid HMR update type");
106
+ const updateMessage = {
107
+ type: "hmr:update",
108
+ code: update.code
109
+ };
110
+ this.send(client, JSON.stringify(updateMessage));
111
+ this.done(client);
112
+ }
113
+ sendReloadToClient(client) {
114
+ this.logger.trace(`Sending HMR reload message to client (clientId: ${client.id})`);
115
+ this.send(client, JSON.stringify({ type: "hmr:reload" }));
116
+ this.done(client);
117
+ }
118
+ done(client) {
119
+ this.send(client, JSON.stringify({ type: "hmr:update-done" }));
120
+ }
121
+ sendError(client, error) {
122
+ try {
123
+ this.send(client, JSON.stringify(error));
124
+ } catch (error) {
125
+ this.logger.error(`Failed to send HMR error message to client (clientId: ${client.id})`, error);
126
+ }
127
+ }
128
+ cleanup(client) {
129
+ this.logger.trace(`HMR client cleanup (clientId: ${client.id})`);
130
+ const binding = this.bindings.get(client.id);
131
+ const instance = this.instances.get(client.id);
132
+ if (binding != null) binding.unsubscribe();
133
+ if (instance != null) try {
134
+ instance.devEngine.removeClient(String(client.id));
135
+ } catch (error) {
136
+ this.logger.warn(`Skipped devEngine.removeClient for client ${client.id}: ` + (error instanceof Error ? error.message : String(error)));
137
+ }
138
+ this.bindings.delete(client.id);
139
+ this.instances.delete(client.id);
140
+ }
141
+ onMessage(client, data) {
142
+ let message;
143
+ try {
144
+ message = this.parseClientMessage(data);
145
+ let traceMessage = message;
146
+ if (message.type === "hmr:module-registered") traceMessage = {
147
+ ...message,
148
+ modules: `[${message.modules.length} modules]`
149
+ };
150
+ else if (message.type === "hmr:log") traceMessage = {
151
+ ...message,
152
+ data: `(${message.data.length} items)`
153
+ };
154
+ this.logger.trace("HMR client message received", traceMessage);
155
+ } catch (error) {
156
+ const message = "Failed to parse HMR client message";
157
+ this.logger.error(message, error);
158
+ this.sendError(client, {
159
+ type: "InternalError",
160
+ errors: [{ description: error instanceof Error ? error.message : String(error) }],
161
+ message
162
+ });
163
+ return;
164
+ }
165
+ if (isCustomHMRMessage(message)) {
166
+ this.wss.emit(message.type, message.payload);
167
+ return;
168
+ }
169
+ switch (message.type) {
170
+ case "hmr:connected":
171
+ this.handleConnected(client, message.platform, message.bundleEntry);
172
+ break;
173
+ case "hmr:module-registered":
174
+ this.handleModuleRegistered(client, message.modules);
175
+ break;
176
+ case "hmr:invalidate":
177
+ this.handleInvalidate(client, message.moduleId);
178
+ break;
179
+ case "hmr:log": {
180
+ const instance = this.instances.get(client.id);
181
+ this.eventBus.emit({
182
+ type: "client_log",
183
+ ...instance != null ? { bundlerId: instance.id } : {},
184
+ level: message.level,
185
+ data: message.data
186
+ });
187
+ break;
188
+ }
189
+ }
190
+ }
191
+ onConnection(client) {
192
+ this.logger.trace(`connection established (clientId: ${client.id})`);
193
+ }
194
+ onError(client, error) {
195
+ this.logger.error(`connection error (clientId: ${client.id})`, error);
196
+ this.cleanup(client);
197
+ }
198
+ onClose(client) {
199
+ this.logger.trace(`connection closed (clientId: ${client.id})`);
200
+ this.cleanup(client);
201
+ }
202
+ };
203
+ function isCustomHMRMessage(message) {
204
+ if (typeof message !== "object" || message == null) return false;
205
+ if ("type" in message && typeof message.type === "string" && message.type.startsWith("hmr:")) return false;
206
+ return true;
207
+ }
208
+ //#endregion
209
+ export { HMRServer };
@@ -0,0 +1,9 @@
1
+ import EventEmitter from "node:events";
2
+ import * as ws from "ws";
3
+
4
+ //#region src/server/wss/server.d.ts
5
+ type WebSocketClient = ws.WebSocket & {
6
+ id: number;
7
+ };
8
+ //#endregion
9
+ export { WebSocketClient };
@@ -0,0 +1,70 @@
1
+ import { logger } from "../logger.js";
2
+ import { parseUrl } from "../../utils/url.js";
3
+ import EventEmitter from "node:events";
4
+ import * as ws from "ws";
5
+ //#region src/server/wss/server.ts
6
+ var WebSocketServer = class extends EventEmitter {
7
+ clientId = 0;
8
+ wss;
9
+ logger;
10
+ constructor(name, options) {
11
+ super();
12
+ const logger$1 = logger.child(name);
13
+ const wss = new ws.WebSocketServer(options);
14
+ wss.on("connection", (socket) => {
15
+ const client = Object.defineProperty(socket, "id", {
16
+ value: this.clientId++,
17
+ writable: false
18
+ });
19
+ this.onConnection(client);
20
+ this.emit("connection", client);
21
+ client.on("message", (data) => {
22
+ this.onMessage(client, data);
23
+ this.emit("message", client, data);
24
+ });
25
+ client.on("error", (error) => {
26
+ this.onError(client, error);
27
+ this.emit("error", client, error);
28
+ });
29
+ client.on("close", () => {
30
+ this.onClose(client);
31
+ this.emit("close", client);
32
+ });
33
+ });
34
+ this.wss = wss;
35
+ this.logger = logger$1;
36
+ }
37
+ get server() {
38
+ return this.wss;
39
+ }
40
+ send(client, data) {
41
+ if (client.readyState === ws.WebSocket.OPEN) client.send(data);
42
+ }
43
+ sendAll(data) {
44
+ this.wss.clients.forEach((client) => {
45
+ if (client.readyState === ws.WebSocket.OPEN) client.send(data);
46
+ });
47
+ }
48
+ rawDataToString(data) {
49
+ if (Buffer.isBuffer(data)) return data.toString("utf8");
50
+ if (Array.isArray(data)) return Buffer.concat(data).toString("utf8");
51
+ return Buffer.from(data).toString("utf8");
52
+ }
53
+ };
54
+ function getWebSocketUpgradeHandler(websocketEndpoints) {
55
+ return (request, socket, head) => {
56
+ if (request.url == null) {
57
+ socket.destroy();
58
+ return;
59
+ }
60
+ const { pathname } = parseUrl(request.url);
61
+ if (pathname != null && websocketEndpoints[pathname]) {
62
+ const wss = websocketEndpoints[pathname];
63
+ wss.handleUpgrade(request, socket, head, (socket) => {
64
+ wss.emit("connection", socket, request);
65
+ });
66
+ } else socket.destroy();
67
+ };
68
+ }
69
+ //#endregion
70
+ export { WebSocketServer, getWebSocketUpgradeHandler };
@@ -73,15 +73,4 @@ interface DevRuntimeMessenger {
73
73
  send(message: HMRClientMessage): void;
74
74
  }
75
75
  //#endregion
76
- //#region src/runtime.d.ts
77
- declare global {
78
- var __ROLLIPOP_CUSTOM_HMR_HANDLER__: HMRCustomHandler | undefined;
79
- }
80
- /**
81
- * Set a custom HMR handler.
82
- *
83
- * @param handler - The custom HMR handler to set.
84
- */
85
- declare function setCustomHMRHandler(handler: HMRCustomHandler): void;
86
- //#endregion
87
- export { setCustomHMRHandler };
76
+ export { type DevRuntime, DevRuntimeInterface, DevRuntimeMessenger, DevRuntimeModule, HMRClientLogLevel, HMRClientMessage, HMRContext, HMRCustomHandler, HMRCustomMessage, HMRServerError, HMRServerMessage };
@@ -0,0 +1,78 @@
1
+ //#region src/types.d.ts
2
+ type MaybePromise<T> = T | Promise<T>;
3
+ type NullValue<T = void> = T | undefined | null | void;
4
+ type DeepRequired<T> = { [K in keyof T]-?: T[K] extends object ? DeepRequired<T[K]> : T[K] };
5
+ interface Reporter {
6
+ update(event: ReportableEvent): void;
7
+ }
8
+ interface OptionalBundlerEvent {
9
+ bundlerId?: string;
10
+ }
11
+ interface BuildDiagnosticLog {
12
+ code?: string;
13
+ plugin?: string;
14
+ message: string;
15
+ stack?: string;
16
+ id?: string;
17
+ hook?: string;
18
+ frame?: string;
19
+ loc?: {
20
+ column: number;
21
+ file?: string;
22
+ line: number;
23
+ };
24
+ meta?: unknown;
25
+ }
26
+ type ReportableEvent = ({
27
+ type: 'bundle_build_started';
28
+ } & OptionalBundlerEvent) | ({
29
+ type: 'bundle_build_done';
30
+ totalModules: number;
31
+ transformedModules: number;
32
+ cacheHitModules: number;
33
+ duration: number;
34
+ bundleFilePath?: string;
35
+ } & OptionalBundlerEvent) | ({
36
+ type: 'bundle_build_failed';
37
+ error: Error;
38
+ } & OptionalBundlerEvent) | ({
39
+ type: 'hmr_failed';
40
+ error: Error;
41
+ } & OptionalBundlerEvent) | ({
42
+ type: 'transform';
43
+ id: string;
44
+ totalModules: number | undefined;
45
+ transformedModules: number;
46
+ } & OptionalBundlerEvent) | ({
47
+ type: 'watch_change';
48
+ id: string;
49
+ } & OptionalBundlerEvent) | ({
50
+ type: 'build_log';
51
+ level: 'debug' | 'info';
52
+ log: BuildDiagnosticLog;
53
+ } & OptionalBundlerEvent) | ({
54
+ type: 'build_error';
55
+ level: 'warn' | 'error';
56
+ log: BuildDiagnosticLog;
57
+ } & OptionalBundlerEvent) | MetroCompatibleClientLogEvent;
58
+ type MetroCompatibleClientLogEvent = {
59
+ type: 'client_log';
60
+ level: 'trace' | 'info' | 'warn' | 'log' | 'group' | 'groupCollapsed' | 'groupEnd' | 'debug'
61
+ /**
62
+ * In react-native, ReportableEvent['level'] does not defined `error` type.
63
+ * But, Flipper supports the `error` type.
64
+ *
65
+ * @see https://github.com/facebook/flipper/blob/v0.273.0/desktop/flipper-common/src/server-types.tsx#L74
66
+ */
67
+ | 'error';
68
+ data: any[];
69
+ bundlerId?: string;
70
+ };
71
+ interface PackageJson {
72
+ name: string;
73
+ version?: string;
74
+ dependencies?: Record<string, string>;
75
+ devDependencies?: Record<string, string>;
76
+ }
77
+ //#endregion
78
+ export { BuildDiagnosticLog, DeepRequired, MaybePromise, MetroCompatibleClientLogEvent, NullValue, PackageJson, ReportableEvent, Reporter };
@@ -0,0 +1,11 @@
1
+ import { mergeWith } from "es-toolkit";
2
+ //#region src/utils/babel.ts
3
+ function mergeBabelOptions(options) {
4
+ return options.reduce((acc, options) => mergeWith(acc, options, merge$1), {});
5
+ }
6
+ function merge$1(target, source, key) {
7
+ if (key === "plugins") return [...target ?? [], ...source ?? []];
8
+ if (key === "presets") return [...target ?? [], ...source ?? []];
9
+ }
10
+ //#endregion
11
+ export { mergeBabelOptions };
@@ -0,0 +1,17 @@
1
+ import path from "node:path";
2
+ import { merge } from "es-toolkit";
3
+ //#region src/utils/build-options.ts
4
+ const DEFAULT_BUILD_OPTIONS = {
5
+ cache: true,
6
+ minify: false
7
+ };
8
+ function resolveBuildOptions(config, buildOptions) {
9
+ if (buildOptions.outfile) buildOptions.outfile = path.resolve(config.root, buildOptions.outfile);
10
+ if ((buildOptions.sourcemap === true || buildOptions.sourcemap === "hidden") && buildOptions.sourcemapOutfile) buildOptions.sourcemapOutfile = path.resolve(config.root, buildOptions.sourcemapOutfile);
11
+ return merge(DEFAULT_BUILD_OPTIONS, {
12
+ ...buildOptions,
13
+ dev: buildOptions.dev ?? config.mode === "development"
14
+ });
15
+ }
16
+ //#endregion
17
+ export { resolveBuildOptions };
@@ -0,0 +1,6 @@
1
+ //#region src/utils/bundle.ts
2
+ function getBaseBundleName(name) {
3
+ return name.replace(/^\//, "").replace(/\.bundle$/, "");
4
+ }
5
+ //#endregion
6
+ export { getBaseBundleName };
@@ -0,0 +1,5 @@
1
+ import { HmrConfig } from "../config/types.js";
2
+ //#region src/utils/config.d.ts
3
+ type ResolvedHmrConfig = Required<HmrConfig>;
4
+ //#endregion
5
+ export { ResolvedHmrConfig };
@@ -0,0 +1,32 @@
1
+ import { __require } from "../_virtual/_rolldown/runtime.js";
2
+ import fs from "node:fs";
3
+ //#region src/utils/config.ts
4
+ function bindReporter(config, onEvent) {
5
+ const reporter = { update(event) {
6
+ onEvent?.(event);
7
+ } };
8
+ return {
9
+ ...config,
10
+ reporter
11
+ };
12
+ }
13
+ function resolveHmrConfig(config) {
14
+ if (config.mode !== "development") return null;
15
+ const defaultRuntimeImplements = getDefaultRuntimeImplements();
16
+ if (typeof config.devMode.hmr === "boolean") return config.devMode.hmr ? defaultRuntimeImplements : null;
17
+ const { runtimeImplement = defaultRuntimeImplements.runtimeImplement, clientImplement = defaultRuntimeImplements.clientImplement } = config.devMode.hmr;
18
+ return {
19
+ runtimeImplement,
20
+ clientImplement
21
+ };
22
+ }
23
+ getDefaultRuntimeImplements.cache = null;
24
+ function getDefaultRuntimeImplements() {
25
+ if (getDefaultRuntimeImplements.cache == null) getDefaultRuntimeImplements.cache = {
26
+ runtimeImplement: fs.readFileSync(__require.resolve("rollipop/hmr-runtime"), "utf-8"),
27
+ clientImplement: fs.readFileSync(__require.resolve("rollipop/hmr-client"), "utf-8")
28
+ };
29
+ return getDefaultRuntimeImplements.cache;
30
+ }
31
+ //#endregion
32
+ export { bindReporter, resolveHmrConfig };