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.
- package/CHANGELOG.md +19 -0
- package/dist/{chunk-DEq-mXcV.js → _virtual/_rolldown/runtime.js} +1 -1
- package/dist/commands.d.ts +2 -4
- package/dist/commands.js +10 -3957
- package/dist/common/code.js +21 -0
- package/dist/common/constants.js +5 -0
- package/dist/common/env.js +33 -0
- package/dist/common/logger.d.ts +34 -0
- package/dist/common/logger.js +82 -0
- package/dist/common/logo.js +54 -0
- package/dist/common/progress-bar.js +167 -0
- package/dist/common/transformer.js +13 -0
- package/dist/common/types.d.ts +10 -0
- package/dist/config/compose-override.js +18 -0
- package/dist/config/defaults.d.ts +74 -0
- package/dist/config/defaults.js +74 -0
- package/dist/config/define-config.d.ts +13 -0
- package/dist/config/define-config.js +6 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +5 -0
- package/dist/config/load-config.d.ts +19 -0
- package/dist/config/load-config.js +73 -0
- package/dist/config/merge-config.d.ts +12 -0
- package/dist/config/merge-config.js +20 -0
- package/dist/config/types.d.ts +452 -0
- package/dist/constants.d.ts +35 -0
- package/dist/constants.js +146 -0
- package/dist/core/assets.d.ts +91 -0
- package/dist/core/assets.js +244 -0
- package/dist/core/bundler.d.ts +15 -0
- package/dist/core/bundler.js +80 -0
- package/dist/core/env.d.ts +11 -0
- package/dist/core/env.js +36 -0
- package/dist/core/fs/data.js +9 -0
- package/dist/core/fs/storage.d.ts +15 -0
- package/dist/core/fs/storage.js +31 -0
- package/dist/core/plugins/babel-plugin.d.ts +22 -0
- package/dist/core/plugins/babel-plugin.js +74 -0
- package/dist/core/plugins/context.d.ts +10 -0
- package/dist/core/plugins/context.js +24 -0
- package/dist/core/plugins/dev-server-plugin.d.ts +13 -0
- package/dist/core/plugins/dev-server-plugin.js +27 -0
- package/dist/core/plugins/index.d.ts +13 -0
- package/dist/core/plugins/index.js +18 -0
- package/dist/core/plugins/prelude-plugin.d.ts +10 -0
- package/dist/core/plugins/prelude-plugin.js +23 -0
- package/dist/core/plugins/react-native-plugin.d.ts +36 -0
- package/dist/core/plugins/react-native-plugin.js +81 -0
- package/dist/core/plugins/reporter-plugin.d.ts +11 -0
- package/dist/core/plugins/reporter-plugin.js +87 -0
- package/dist/core/plugins/shared/filters.js +5 -0
- package/dist/core/plugins/swc-plugin.d.ts +26 -0
- package/dist/core/plugins/swc-plugin.js +108 -0
- package/dist/core/plugins/types.d.ts +18 -0
- package/dist/core/plugins/utils/source.js +10 -0
- package/dist/core/plugins/utils/transform-utils.js +56 -0
- package/dist/core/rolldown.js +313 -0
- package/dist/core/settings.js +19 -0
- package/dist/core/types.d.ts +83 -0
- package/dist/filter.d.ts +1 -0
- package/dist/filter.js +2 -0
- package/dist/hmr-runtime.iife.js +5 -5
- package/dist/index.d.ts +24 -1221
- package/dist/index.js +19 -4029
- package/dist/internal/react-native.js +24 -0
- package/dist/logger.js +5 -0
- package/dist/node/cli-utils.d.ts +10 -0
- package/dist/node/cli-utils.js +28 -0
- package/dist/node/cli.d.ts +6 -0
- package/dist/node/cli.js +23 -0
- package/dist/node/commands/agent/action.js +91 -0
- package/dist/node/commands/agent/command.js +10 -0
- package/dist/node/commands/agent/index.js +2 -0
- package/dist/node/commands/bundle/action.js +33 -0
- package/dist/node/commands/bundle/command.js +96 -0
- package/dist/node/commands/bundle/index.js +2 -0
- package/dist/node/commands/start/action.js +37 -0
- package/dist/node/commands/start/command.js +93 -0
- package/dist/node/commands/start/debugger.js +79 -0
- package/dist/node/commands/start/index.js +2 -0
- package/dist/node/commands/start/setup-interactive-mode.d.ts +20 -0
- package/dist/node/commands/start/setup-interactive-mode.js +107 -0
- package/dist/node/constants.js +4 -0
- package/dist/node/logger.js +5 -0
- package/dist/node/types.d.ts +23 -0
- package/dist/node/utils.js +23 -0
- package/dist/package.js +4 -0
- package/dist/runtime.js +1 -1
- package/dist/server/bundle.d.ts +12 -0
- package/dist/server/bundle.js +55 -0
- package/dist/server/bundler-pool.d.ts +51 -0
- package/dist/server/bundler-pool.js +197 -0
- package/dist/server/common/schema.js +19 -0
- package/dist/server/constants.d.ts +6 -0
- package/dist/server/constants.js +6 -0
- package/dist/server/create-dev-server.d.ts +6 -0
- package/dist/server/create-dev-server.js +185 -0
- package/dist/server/error.js +9 -0
- package/dist/server/events/event-bus.d.ts +12 -0
- package/dist/server/events/event-bus.js +16 -0
- package/dist/server/events/types.d.ts +37 -0
- package/dist/server/events/types.js +6 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +3 -0
- package/dist/server/logger.js +33 -0
- package/dist/server/mcp/context.js +14 -0
- package/dist/server/mcp/server.js +86 -0
- package/dist/server/mcp/tools/app-log-diagnostics.js +37 -0
- package/dist/server/mcp/tools/build-diagnostics.js +97 -0
- package/dist/server/mcp/tools/build-info.js +33 -0
- package/dist/server/mcp/tools/device-diagnostics.js +52 -0
- package/dist/server/mcp/tools/index.js +277 -0
- package/dist/server/middlewares/request-logger.js +15 -0
- package/dist/server/middlewares/serve-assets.js +49 -0
- package/dist/server/middlewares/serve-bundle.js +72 -0
- package/dist/server/middlewares/sse.js +34 -0
- package/dist/server/middlewares/symbolicate.js +71 -0
- package/dist/server/sse/adapter.js +74 -0
- package/dist/server/sse/event-bus.js +26 -0
- package/dist/server/symbolicate.js +93 -0
- package/dist/server/types.d.ts +125 -0
- package/dist/server/wss/hmr-server.js +209 -0
- package/dist/server/wss/server.d.ts +9 -0
- package/dist/server/wss/server.js +70 -0
- package/dist/{runtime.d.cts → types/hmr.d.ts} +1 -12
- package/dist/types.d.ts +78 -0
- package/dist/utils/babel.js +11 -0
- package/dist/utils/build-options.js +17 -0
- package/dist/utils/bundle.js +6 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +32 -0
- package/dist/utils/dev-server.js +51 -0
- package/dist/utils/env.js +7 -0
- package/dist/utils/errors.js +9 -0
- package/dist/utils/hash.js +8 -0
- package/dist/utils/id.js +28 -0
- package/dist/utils/node-resolve.js +42 -0
- package/dist/utils/promise.js +15 -0
- package/dist/utils/reporters.js +120 -0
- package/dist/utils/reset-cache.d.ts +8 -0
- package/dist/utils/reset-cache.js +25 -0
- package/dist/utils/response.js +91 -0
- package/dist/utils/run-build.d.ts +8 -0
- package/dist/utils/run-build.js +7 -0
- package/dist/utils/run-server.d.ts +6 -0
- package/dist/utils/run-server.js +20 -0
- package/dist/utils/runtime-target.js +9 -0
- package/dist/utils/serialize.js +10 -0
- package/dist/utils/server.js +6 -0
- package/dist/utils/storage.js +6 -0
- package/dist/utils/string.js +6 -0
- package/dist/utils/swc.js +10 -0
- package/dist/utils/terminal.js +86 -0
- package/dist/utils/url.js +23 -0
- package/package.json +56 -68
- package/dist/commands.cjs +0 -4008
- package/dist/commands.d.cts +0 -5
- package/dist/pluginutils.d.ts +0 -1
- package/dist/pluginutils.js +0 -2
- package/dist/runtime.cjs +0 -34
- /package/dist/{chunk-DXpK5_cz.js → chunk-DJV587Yu.js} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createPluginContext } from "../core/plugins/context.js";
|
|
2
|
+
import { DevServerLogger, logger } from "./logger.js";
|
|
3
|
+
import { assertDevServerStatus } from "../utils/dev-server.js";
|
|
4
|
+
import { BundlerPool } from "./bundler-pool.js";
|
|
5
|
+
import { DEFAULT_HOST, DEFAULT_PORT } from "./constants.js";
|
|
6
|
+
import { errorHandler } from "./error.js";
|
|
7
|
+
import { ServerEventBus } from "./events/event-bus.js";
|
|
8
|
+
import { toSSEEvent } from "./sse/adapter.js";
|
|
9
|
+
import { plugin } from "./mcp/server.js";
|
|
10
|
+
import { requestLogger } from "./middlewares/request-logger.js";
|
|
11
|
+
import { plugin as plugin$1 } from "./middlewares/serve-assets.js";
|
|
12
|
+
import { plugin as plugin$2 } from "./middlewares/serve-bundle.js";
|
|
13
|
+
import { SSEEventPublisher } from "./sse/event-bus.js";
|
|
14
|
+
import { plugin as plugin$3 } from "./middlewares/sse.js";
|
|
15
|
+
import { plugin as plugin$4 } from "./middlewares/symbolicate.js";
|
|
16
|
+
import { getWebSocketUpgradeHandler } from "./wss/server.js";
|
|
17
|
+
import { HMRServer } from "./wss/hmr-server.js";
|
|
18
|
+
import url from "url";
|
|
19
|
+
import { createDevServerMiddleware } from "@react-native-community/cli-server-api";
|
|
20
|
+
import { createDevMiddleware } from "@react-native/dev-middleware";
|
|
21
|
+
import Fastify from "fastify";
|
|
22
|
+
import mitt from "mitt";
|
|
23
|
+
//#region src/server/create-dev-server.ts
|
|
24
|
+
async function createDevServer(config, options) {
|
|
25
|
+
const projectRoot = config.root;
|
|
26
|
+
const { port = DEFAULT_PORT, host = DEFAULT_HOST, https = false } = options ?? {};
|
|
27
|
+
if (https) throw new Error("HTTPS is not supported yet");
|
|
28
|
+
const serverBaseUrl = url.format({
|
|
29
|
+
protocol: https ? "https" : "http",
|
|
30
|
+
hostname: host,
|
|
31
|
+
port
|
|
32
|
+
});
|
|
33
|
+
await assertDevServerStatus({
|
|
34
|
+
devServerUrl: serverBaseUrl,
|
|
35
|
+
projectRoot,
|
|
36
|
+
port
|
|
37
|
+
});
|
|
38
|
+
const emitter = mitt();
|
|
39
|
+
const fastify = Fastify({
|
|
40
|
+
loggerInstance: new DevServerLogger(),
|
|
41
|
+
disableRequestLogging: true
|
|
42
|
+
});
|
|
43
|
+
const eventBus = new ServerEventBus();
|
|
44
|
+
const bundlerPool = new BundlerPool(config, {
|
|
45
|
+
host,
|
|
46
|
+
port
|
|
47
|
+
}, eventBus);
|
|
48
|
+
const ssePublisher = new SSEEventPublisher();
|
|
49
|
+
const reporter = config.reporter;
|
|
50
|
+
eventBus.subscribe((event) => {
|
|
51
|
+
const sseEvent = toSSEEvent(event);
|
|
52
|
+
if (sseEvent != null) ssePublisher.publish(sseEvent);
|
|
53
|
+
});
|
|
54
|
+
const { middleware: communityMiddleware, websocketEndpoints: communityWebsocketEndpoints, messageSocketEndpoint: { server: messageServer, broadcast }, eventsSocketEndpoint: { server: eventsServer, reportEvent } } = createDevServerMiddleware({
|
|
55
|
+
port,
|
|
56
|
+
host,
|
|
57
|
+
watchFolders: []
|
|
58
|
+
});
|
|
59
|
+
eventBus.subscribe((event) => {
|
|
60
|
+
switch (event.type) {
|
|
61
|
+
case "bundle_build_started":
|
|
62
|
+
case "bundle_build_done":
|
|
63
|
+
case "bundle_build_failed":
|
|
64
|
+
case "hmr_failed":
|
|
65
|
+
case "build_log":
|
|
66
|
+
case "build_error":
|
|
67
|
+
case "transform":
|
|
68
|
+
case "watch_change":
|
|
69
|
+
reporter?.update(event);
|
|
70
|
+
break;
|
|
71
|
+
case "client_log":
|
|
72
|
+
reportEvent?.(event);
|
|
73
|
+
reporter?.update(event);
|
|
74
|
+
break;
|
|
75
|
+
case "device_connected":
|
|
76
|
+
emitter.emit("device.connected", { client: event.client });
|
|
77
|
+
break;
|
|
78
|
+
case "device_message":
|
|
79
|
+
emitter.emit("device.message", {
|
|
80
|
+
client: event.client,
|
|
81
|
+
data: event.data
|
|
82
|
+
});
|
|
83
|
+
break;
|
|
84
|
+
case "device_error":
|
|
85
|
+
emitter.emit("device.error", {
|
|
86
|
+
client: event.client,
|
|
87
|
+
error: event.error
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
case "device_disconnected":
|
|
91
|
+
emitter.emit("device.disconnected", { client: event.client });
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const { middleware: devMiddleware, websocketEndpoints } = createDevMiddleware({
|
|
96
|
+
serverBaseUrl,
|
|
97
|
+
logger: {
|
|
98
|
+
info(...args) {
|
|
99
|
+
if (args[0].includes("JavaScript logs have moved")) return;
|
|
100
|
+
logger.info(...args);
|
|
101
|
+
},
|
|
102
|
+
warn: logger.warn.bind(logger),
|
|
103
|
+
error: logger.error.bind(logger)
|
|
104
|
+
},
|
|
105
|
+
unstable_experiments: {
|
|
106
|
+
enableNetworkInspector: true,
|
|
107
|
+
enableStandaloneFuseboxShell: true
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const hmrServer = new HMRServer({
|
|
111
|
+
bundlerPool,
|
|
112
|
+
eventBus
|
|
113
|
+
}).on("connection", (client) => eventBus.emit({
|
|
114
|
+
type: "device_connected",
|
|
115
|
+
client
|
|
116
|
+
})).on("message", (client, data) => eventBus.emit({
|
|
117
|
+
type: "device_message",
|
|
118
|
+
client,
|
|
119
|
+
data
|
|
120
|
+
})).on("error", (client, error) => eventBus.emit({
|
|
121
|
+
type: "device_error",
|
|
122
|
+
client,
|
|
123
|
+
error
|
|
124
|
+
})).on("close", (client) => eventBus.emit({
|
|
125
|
+
type: "device_disconnected",
|
|
126
|
+
client
|
|
127
|
+
}));
|
|
128
|
+
await fastify.register(import("@fastify/middie"));
|
|
129
|
+
const context = {
|
|
130
|
+
serverBaseUrl,
|
|
131
|
+
config: Object.freeze(config),
|
|
132
|
+
options: Object.freeze(options ?? {}),
|
|
133
|
+
bundlerPool,
|
|
134
|
+
eventBus,
|
|
135
|
+
message: Object.assign(messageServer, { broadcast }),
|
|
136
|
+
events: Object.assign(eventsServer, { reportEvent }),
|
|
137
|
+
hot: Object.assign(hmrServer.server, {
|
|
138
|
+
send: (client, eventName, payload) => {
|
|
139
|
+
hmrServer.send(client, JSON.stringify({
|
|
140
|
+
type: eventName,
|
|
141
|
+
payload
|
|
142
|
+
}));
|
|
143
|
+
},
|
|
144
|
+
sendAll: (eventName, payload) => {
|
|
145
|
+
hmrServer.sendAll(JSON.stringify({
|
|
146
|
+
type: eventName,
|
|
147
|
+
payload
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
};
|
|
152
|
+
const devServer = {
|
|
153
|
+
...context,
|
|
154
|
+
...emitter,
|
|
155
|
+
instance: fastify,
|
|
156
|
+
middlewares: { use: fastify.use.bind(fastify) }
|
|
157
|
+
};
|
|
158
|
+
const { invokePostConfigureServer } = await invokeConfigureServer(devServer, config.plugins ?? []);
|
|
159
|
+
fastify.use(requestLogger).use(communityMiddleware).use(devMiddleware).register(plugin$4, { context }).register(plugin$2, { context }).register(plugin$1, { context }).register(plugin$3, { context }).register(plugin, { context }).setErrorHandler(errorHandler);
|
|
160
|
+
fastify.server.on("upgrade", getWebSocketUpgradeHandler({
|
|
161
|
+
...communityWebsocketEndpoints,
|
|
162
|
+
...websocketEndpoints,
|
|
163
|
+
"/hot": hmrServer.server
|
|
164
|
+
}));
|
|
165
|
+
await invokePostConfigureServer();
|
|
166
|
+
eventBus.emit({
|
|
167
|
+
type: "server_ready",
|
|
168
|
+
host,
|
|
169
|
+
port
|
|
170
|
+
});
|
|
171
|
+
return devServer;
|
|
172
|
+
}
|
|
173
|
+
async function invokeConfigureServer(server, plugins) {
|
|
174
|
+
const postConfigureServerHandlers = [];
|
|
175
|
+
for (const plugin of plugins) {
|
|
176
|
+
const context = createPluginContext(plugin.name);
|
|
177
|
+
const result = await plugin.configureServer?.call(context, server);
|
|
178
|
+
if (typeof result === "function") postConfigureServerHandlers.push(result);
|
|
179
|
+
}
|
|
180
|
+
return { invokePostConfigureServer: async () => {
|
|
181
|
+
for (const handler of postConfigureServerHandlers) await handler();
|
|
182
|
+
} };
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
export { createDevServer };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { logger } from "./logger.js";
|
|
2
|
+
//#region src/server/error.ts
|
|
3
|
+
function errorHandler(error, request, reply) {
|
|
4
|
+
logger.error(`An error occurred while processing the request (${request.method} ${request.url}):`, error.message);
|
|
5
|
+
logger.debug(error);
|
|
6
|
+
reply.status(500).send("Internal Server Error");
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { errorHandler };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ServerEvent } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/events/event-bus.d.ts
|
|
4
|
+
type EventListener<Event> = (event: Event) => void;
|
|
5
|
+
declare class EventBus<Event> {
|
|
6
|
+
private listeners;
|
|
7
|
+
emit(event: Event): void;
|
|
8
|
+
subscribe(listener: EventListener<Event>): () => void;
|
|
9
|
+
}
|
|
10
|
+
declare class ServerEventBus extends EventBus<ServerEvent> {}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { ServerEventBus };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/server/events/event-bus.ts
|
|
2
|
+
var EventBus = class {
|
|
3
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4
|
+
emit(event) {
|
|
5
|
+
for (const listener of this.listeners) listener(event);
|
|
6
|
+
}
|
|
7
|
+
subscribe(listener) {
|
|
8
|
+
this.listeners.add(listener);
|
|
9
|
+
return () => {
|
|
10
|
+
this.listeners.delete(listener);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var ServerEventBus = class extends EventBus {};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { ServerEventBus };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { MetroCompatibleClientLogEvent, ReportableEvent } from "../../types.js";
|
|
2
|
+
import { WebSocketClient } from "../wss/server.js";
|
|
3
|
+
import * as rolldownExperimental from "@rollipop/rolldown/experimental";
|
|
4
|
+
import * as ws from "ws";
|
|
5
|
+
|
|
6
|
+
//#region src/server/events/types.d.ts
|
|
7
|
+
type IdentifiedReportableEvent = ReportableEvent & {
|
|
8
|
+
bundlerId: string;
|
|
9
|
+
};
|
|
10
|
+
type BundlerEvent = IdentifiedReportableEvent | {
|
|
11
|
+
type: 'hmr_updates';
|
|
12
|
+
bundlerId: string;
|
|
13
|
+
updates: rolldownExperimental.BindingClientHmrUpdate[];
|
|
14
|
+
};
|
|
15
|
+
type ServerEvent = BundlerEvent | MetroCompatibleClientLogEvent | {
|
|
16
|
+
type: 'device_connected';
|
|
17
|
+
client: WebSocketClient;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'device_message';
|
|
20
|
+
client: WebSocketClient;
|
|
21
|
+
data: ws.RawData;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'device_error';
|
|
24
|
+
client: WebSocketClient;
|
|
25
|
+
error: Error;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'device_disconnected';
|
|
28
|
+
client: WebSocketClient;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'server_ready';
|
|
31
|
+
host: string;
|
|
32
|
+
port: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'cache_reset';
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ServerEvent };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BundleDetails, DevServer, DevServerContext, DevServerEvents, FastifyInstance, FormattedError, Middlewares, ServerOptions } from "./types.js";
|
|
2
|
+
import { createDevServer } from "./create-dev-server.js";
|
|
3
|
+
import { DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH } from "./constants.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Logger } from "../common/logger.js";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
//#region src/server/logger.ts
|
|
4
|
+
const logger = new Logger("dev-server");
|
|
5
|
+
var DevServerLogger = class {
|
|
6
|
+
level = "trace";
|
|
7
|
+
trace(...args) {
|
|
8
|
+
logger.trace(...args);
|
|
9
|
+
}
|
|
10
|
+
debug(...args) {
|
|
11
|
+
logger.debug(...args);
|
|
12
|
+
}
|
|
13
|
+
info(...args) {
|
|
14
|
+
logger.info(...args);
|
|
15
|
+
}
|
|
16
|
+
warn(...args) {
|
|
17
|
+
logger.warn(...args);
|
|
18
|
+
}
|
|
19
|
+
error(...args) {
|
|
20
|
+
logger.error(...args);
|
|
21
|
+
}
|
|
22
|
+
silent(...args) {
|
|
23
|
+
logger.trace(chalk.gray("(silent)"), ...args);
|
|
24
|
+
}
|
|
25
|
+
fatal(...args) {
|
|
26
|
+
logger.error(chalk.magenta("(fatal)"), ...args);
|
|
27
|
+
}
|
|
28
|
+
child(_bindings) {
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { DevServerLogger, logger };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AppLogDiagnostics } from "./tools/app-log-diagnostics.js";
|
|
2
|
+
import { BuildDiagnostics } from "./tools/build-diagnostics.js";
|
|
3
|
+
import { DeviceDiagnostics } from "./tools/device-diagnostics.js";
|
|
4
|
+
//#region src/server/mcp/context.ts
|
|
5
|
+
function createMcpToolContext(context) {
|
|
6
|
+
return {
|
|
7
|
+
context,
|
|
8
|
+
appLogDiagnostics: new AppLogDiagnostics(context),
|
|
9
|
+
buildDiagnostics: new BuildDiagnostics(context),
|
|
10
|
+
deviceDiagnostics: new DeviceDiagnostics(context)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { createMcpToolContext };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createMcpToolContext } from "./context.js";
|
|
2
|
+
import { registerTools } from "./tools/index.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
6
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import fp from "fastify-plugin";
|
|
8
|
+
//#region src/server/mcp/server.ts
|
|
9
|
+
function createMcpServer(options) {
|
|
10
|
+
const server = new McpServer({
|
|
11
|
+
name: "rollipop",
|
|
12
|
+
version: "1.0.0-alpha.23"
|
|
13
|
+
}, { capabilities: { logging: {} } });
|
|
14
|
+
registerTools(server, options);
|
|
15
|
+
return server;
|
|
16
|
+
}
|
|
17
|
+
const plugin = fp((fastify, options) => {
|
|
18
|
+
const { context } = options;
|
|
19
|
+
if (context.options.mcp !== true) {
|
|
20
|
+
fastify.all("/mcp", async (_request, reply) => {
|
|
21
|
+
return reply.status(503).send({ error: {
|
|
22
|
+
code: "MCP_DISABLED",
|
|
23
|
+
message: "MCP server is disabled. Start Rollipop with --mcp to enable it."
|
|
24
|
+
} });
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const toolContext = createMcpToolContext(context);
|
|
29
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
30
|
+
fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
|
|
31
|
+
try {
|
|
32
|
+
done(null, JSON.parse(body));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
done(error, void 0);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
fastify.post("/mcp", async (request, reply) => {
|
|
38
|
+
const sessionId = request.headers["mcp-session-id"];
|
|
39
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
40
|
+
const { transport } = sessions.get(sessionId);
|
|
41
|
+
await transport.handleRequest(request.raw, reply.raw, request.body);
|
|
42
|
+
return reply;
|
|
43
|
+
}
|
|
44
|
+
if (!sessionId && isInitializeRequest(request.body)) {
|
|
45
|
+
const transport = new StreamableHTTPServerTransport({
|
|
46
|
+
sessionIdGenerator: () => randomUUID(),
|
|
47
|
+
onsessioninitialized: (sid) => {
|
|
48
|
+
sessions.set(sid, {
|
|
49
|
+
transport,
|
|
50
|
+
server
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
transport.onclose = () => {
|
|
55
|
+
const sid = transport.sessionId;
|
|
56
|
+
if (sid) sessions.delete(sid);
|
|
57
|
+
};
|
|
58
|
+
const server = createMcpServer(toolContext);
|
|
59
|
+
await server.connect(transport);
|
|
60
|
+
await transport.handleRequest(request.raw, reply.raw, request.body);
|
|
61
|
+
return reply;
|
|
62
|
+
}
|
|
63
|
+
return reply.status(400).send({
|
|
64
|
+
jsonrpc: "2.0",
|
|
65
|
+
error: {
|
|
66
|
+
code: -32e3,
|
|
67
|
+
message: "Bad Request: invalid or missing session"
|
|
68
|
+
},
|
|
69
|
+
id: null
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
fastify.get("/mcp", async (request, reply) => {
|
|
73
|
+
const sessionId = request.headers["mcp-session-id"];
|
|
74
|
+
if (!sessionId || !sessions.has(sessionId)) return reply.status(400).send("Missing or invalid session ID");
|
|
75
|
+
await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
|
|
76
|
+
return reply;
|
|
77
|
+
});
|
|
78
|
+
fastify.delete("/mcp", async (request, reply) => {
|
|
79
|
+
const sessionId = request.headers["mcp-session-id"];
|
|
80
|
+
if (!sessionId || !sessions.has(sessionId)) return reply.status(404).send("Session not found");
|
|
81
|
+
await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
|
|
82
|
+
return reply;
|
|
83
|
+
});
|
|
84
|
+
}, { name: "mcp" });
|
|
85
|
+
//#endregion
|
|
86
|
+
export { plugin };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/server/mcp/tools/app-log-diagnostics.ts
|
|
2
|
+
const MAX_DIAGNOSTIC_ENTRIES = 500;
|
|
3
|
+
var AppLogDiagnostics = class {
|
|
4
|
+
logs = [];
|
|
5
|
+
nextLogId = 0;
|
|
6
|
+
constructor(context) {
|
|
7
|
+
context.eventBus.subscribe((event) => {
|
|
8
|
+
if (event.type !== "client_log") return;
|
|
9
|
+
this.logs.push({
|
|
10
|
+
id: ++this.nextLogId,
|
|
11
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12
|
+
source: "client_log",
|
|
13
|
+
level: event.level,
|
|
14
|
+
args: event.data,
|
|
15
|
+
...event.bundlerId != null ? { bundlerId: event.bundlerId } : {}
|
|
16
|
+
});
|
|
17
|
+
trimArray(this.logs, MAX_DIAGNOSTIC_ENTRIES);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
getConsoleLogs(options) {
|
|
21
|
+
return filterByBundlerId(this.logs, options?.bundlerId).slice(-(options?.limit ?? 100));
|
|
22
|
+
}
|
|
23
|
+
clearConsoleLogs(options) {
|
|
24
|
+
this.logs = filterOutBundlerId(this.logs, options?.bundlerId);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function trimArray(entries, maxEntries) {
|
|
28
|
+
if (entries.length > maxEntries) entries.splice(0, entries.length - maxEntries);
|
|
29
|
+
}
|
|
30
|
+
function filterByBundlerId(entries, bundlerId) {
|
|
31
|
+
return bundlerId == null ? entries : entries.filter((entry) => entry.bundlerId === bundlerId);
|
|
32
|
+
}
|
|
33
|
+
function filterOutBundlerId(entries, bundlerId) {
|
|
34
|
+
return bundlerId == null ? [] : entries.filter((entry) => entry.bundlerId !== bundlerId);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { AppLogDiagnostics };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//#region src/server/mcp/tools/build-diagnostics.ts
|
|
2
|
+
const MAX_DIAGNOSTIC_ENTRIES = 500;
|
|
3
|
+
var BuildDiagnostics = class {
|
|
4
|
+
buildLogs = [];
|
|
5
|
+
buildErrors = [];
|
|
6
|
+
nextBuildLogId = 0;
|
|
7
|
+
nextBuildErrorId = 0;
|
|
8
|
+
constructor(context) {
|
|
9
|
+
context.eventBus.subscribe((event) => {
|
|
10
|
+
switch (event.type) {
|
|
11
|
+
case "build_log":
|
|
12
|
+
this.pushBuildLog({
|
|
13
|
+
source: "rolldown",
|
|
14
|
+
level: event.level,
|
|
15
|
+
bundlerId: event.bundlerId,
|
|
16
|
+
log: event.log
|
|
17
|
+
});
|
|
18
|
+
break;
|
|
19
|
+
case "build_error":
|
|
20
|
+
this.pushBuildError({
|
|
21
|
+
source: "rolldown",
|
|
22
|
+
level: event.level,
|
|
23
|
+
bundlerId: event.bundlerId,
|
|
24
|
+
log: event.log
|
|
25
|
+
});
|
|
26
|
+
break;
|
|
27
|
+
case "bundle_build_failed":
|
|
28
|
+
this.pushBuildError({
|
|
29
|
+
source: "build",
|
|
30
|
+
level: "error",
|
|
31
|
+
bundlerId: event.bundlerId,
|
|
32
|
+
error: serializeError(event.error)
|
|
33
|
+
});
|
|
34
|
+
break;
|
|
35
|
+
case "hmr_failed":
|
|
36
|
+
this.pushBuildError({
|
|
37
|
+
source: "hmr",
|
|
38
|
+
level: "error",
|
|
39
|
+
bundlerId: event.bundlerId,
|
|
40
|
+
error: serializeError(event.error)
|
|
41
|
+
});
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
getBuildLogs(options) {
|
|
47
|
+
return filterByBundlerId(this.buildLogs, options?.bundlerId).slice(-(options?.limit ?? 100));
|
|
48
|
+
}
|
|
49
|
+
getBuildErrors(options) {
|
|
50
|
+
return filterByBundlerId(this.buildErrors, options?.bundlerId).slice(-(options?.limit ?? 100));
|
|
51
|
+
}
|
|
52
|
+
clearBuildLogs(options) {
|
|
53
|
+
this.buildLogs = filterOutBundlerId(this.buildLogs, options?.bundlerId);
|
|
54
|
+
}
|
|
55
|
+
clearBuildErrors(options) {
|
|
56
|
+
this.buildErrors = filterOutBundlerId(this.buildErrors, options?.bundlerId);
|
|
57
|
+
}
|
|
58
|
+
clearBuildDiagnostics(options) {
|
|
59
|
+
this.clearBuildLogs(options);
|
|
60
|
+
this.clearBuildErrors(options);
|
|
61
|
+
}
|
|
62
|
+
pushBuildLog(log) {
|
|
63
|
+
this.buildLogs.push({
|
|
64
|
+
id: ++this.nextBuildLogId,
|
|
65
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
66
|
+
...log
|
|
67
|
+
});
|
|
68
|
+
trimArray(this.buildLogs, MAX_DIAGNOSTIC_ENTRIES);
|
|
69
|
+
}
|
|
70
|
+
pushBuildError(error) {
|
|
71
|
+
this.buildErrors.push({
|
|
72
|
+
id: ++this.nextBuildErrorId,
|
|
73
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
74
|
+
...error
|
|
75
|
+
});
|
|
76
|
+
trimArray(this.buildErrors, MAX_DIAGNOSTIC_ENTRIES);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
function serializeError(error) {
|
|
80
|
+
if (error instanceof Error) return {
|
|
81
|
+
name: error.name,
|
|
82
|
+
message: error.message,
|
|
83
|
+
stack: error.stack
|
|
84
|
+
};
|
|
85
|
+
return { message: String(error) };
|
|
86
|
+
}
|
|
87
|
+
function trimArray(entries, maxEntries) {
|
|
88
|
+
if (entries.length > maxEntries) entries.splice(0, entries.length - maxEntries);
|
|
89
|
+
}
|
|
90
|
+
function filterByBundlerId(entries, bundlerId) {
|
|
91
|
+
return bundlerId == null ? entries : entries.filter((entry) => entry.bundlerId === bundlerId);
|
|
92
|
+
}
|
|
93
|
+
function filterOutBundlerId(entries, bundlerId) {
|
|
94
|
+
return bundlerId == null ? [] : entries.filter((entry) => entry.bundlerId !== bundlerId);
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { BuildDiagnostics };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { loadEnv } from "../../../core/env.js";
|
|
2
|
+
//#region src/server/mcp/tools/build-info.ts
|
|
3
|
+
function getBuildInfo(config) {
|
|
4
|
+
return toJsonSafe({
|
|
5
|
+
...config,
|
|
6
|
+
env: loadEnv(config)
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function toJsonSafe(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
10
|
+
if (value == null) return value;
|
|
11
|
+
switch (typeof value) {
|
|
12
|
+
case "string":
|
|
13
|
+
case "number":
|
|
14
|
+
case "boolean": return value;
|
|
15
|
+
case "bigint":
|
|
16
|
+
case "symbol": return String(value);
|
|
17
|
+
case "function": return `[Function ${value.name || "anonymous"}]`;
|
|
18
|
+
}
|
|
19
|
+
if (value instanceof Date) return value.toISOString();
|
|
20
|
+
if (value instanceof Error) return {
|
|
21
|
+
name: value.name,
|
|
22
|
+
message: value.message,
|
|
23
|
+
stack: value.stack
|
|
24
|
+
};
|
|
25
|
+
if (seen.has(value)) return "[Circular]";
|
|
26
|
+
seen.add(value);
|
|
27
|
+
if (Array.isArray(value)) return value.map((item) => toJsonSafe(item, seen));
|
|
28
|
+
if (value instanceof Map) return Object.fromEntries(Array.from(value.entries()).map(([key, item]) => [String(key), toJsonSafe(item, seen)]));
|
|
29
|
+
if (value instanceof Set) return Array.from(value.values()).map((item) => toJsonSafe(item, seen));
|
|
30
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toJsonSafe(item, seen)]));
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { getBuildInfo };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/server/mcp/tools/device-diagnostics.ts
|
|
2
|
+
var DeviceDiagnostics = class {
|
|
3
|
+
devices = /* @__PURE__ */ new Map();
|
|
4
|
+
constructor(context) {
|
|
5
|
+
context.eventBus.subscribe((event) => {
|
|
6
|
+
switch (event.type) {
|
|
7
|
+
case "device_connected":
|
|
8
|
+
this.devices.set(event.client.id, {
|
|
9
|
+
id: event.client.id,
|
|
10
|
+
connected: true,
|
|
11
|
+
connectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12
|
+
});
|
|
13
|
+
break;
|
|
14
|
+
case "device_message":
|
|
15
|
+
this.updateDeviceFromMessage(event.client.id, event.data);
|
|
16
|
+
break;
|
|
17
|
+
case "device_disconnected": {
|
|
18
|
+
const device = this.devices.get(event.client.id);
|
|
19
|
+
if (device != null) this.devices.set(event.client.id, {
|
|
20
|
+
...device,
|
|
21
|
+
connected: false,
|
|
22
|
+
disconnectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23
|
+
});
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
getDevices() {
|
|
30
|
+
return Array.from(this.devices.values());
|
|
31
|
+
}
|
|
32
|
+
updateDeviceFromMessage(clientId, data) {
|
|
33
|
+
const device = this.devices.get(clientId);
|
|
34
|
+
if (device == null) return;
|
|
35
|
+
try {
|
|
36
|
+
const message = JSON.parse(rawDataToString(data));
|
|
37
|
+
if (message.type !== "hmr:connected") return;
|
|
38
|
+
this.devices.set(clientId, {
|
|
39
|
+
...device,
|
|
40
|
+
platform: message.platform,
|
|
41
|
+
bundleEntry: message.bundleEntry
|
|
42
|
+
});
|
|
43
|
+
} catch {}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function rawDataToString(data) {
|
|
47
|
+
if (Buffer.isBuffer(data)) return data.toString("utf8");
|
|
48
|
+
if (Array.isArray(data)) return Buffer.concat(data).toString("utf8");
|
|
49
|
+
return Buffer.from(data).toString("utf8");
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DeviceDiagnostics };
|