rollipop 1.0.0-alpha.21 → 1.0.0-alpha.22

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/commands.cjs CHANGED
@@ -46,8 +46,6 @@ let mitt = require("mitt");
46
46
  mitt = __toESM(mitt);
47
47
  let node_http = require("node:http");
48
48
  node_http = __toESM(node_http);
49
- let node_events = require("node:events");
50
- node_events = __toESM(node_events);
51
49
  let _rollipop_rolldown = require("@rollipop/rolldown");
52
50
  _rollipop_rolldown = __toESM(_rollipop_rolldown);
53
51
  let _rollipop_rolldown_experimental = require("@rollipop/rolldown/experimental");
@@ -86,6 +84,8 @@ mime = __toESM(mime);
86
84
  let ajv = require("ajv");
87
85
  ajv = __toESM(ajv);
88
86
  let _babel_code_frame = require("@babel/code-frame");
87
+ let node_events = require("node:events");
88
+ node_events = __toESM(node_events);
89
89
  let ws = require("ws");
90
90
  ws = __toESM(ws);
91
91
  let c12 = require("c12");
@@ -831,30 +831,14 @@ function getGlobalVariables(dev, buildType) {
831
831
  }
832
832
  //#endregion
833
833
  //#region src/utils/config.ts
834
- function bindReporter(config, eventSource, onEvent) {
835
- const originalReporter = config.reporter;
836
- config.reporter = { update(event) {
837
- switch (event.type) {
838
- case "bundle_build_started":
839
- eventSource.emit("buildStart");
840
- break;
841
- case "bundle_build_done":
842
- eventSource.emit("buildDone");
843
- break;
844
- case "bundle_build_failed":
845
- eventSource.emit("buildFailed", event.error);
846
- break;
847
- case "transform":
848
- eventSource.emit("transform", event.id, event.totalModules, event.transformedModules);
849
- break;
850
- case "watch_change":
851
- eventSource.emit("watchChange", event.id);
852
- break;
853
- }
854
- originalReporter?.update(event);
834
+ function bindReporter(config, onEvent) {
835
+ const reporter = { update(event) {
855
836
  onEvent?.(event);
856
837
  } };
857
- return config;
838
+ return {
839
+ ...config,
840
+ reporter
841
+ };
858
842
  }
859
843
  function resolveHmrConfig(config) {
860
844
  if (config.mode !== "development") return null;
@@ -1193,6 +1177,8 @@ var ProgressBarStatusReporter = class {
1193
1177
  update(event) {
1194
1178
  switch (event.type) {
1195
1179
  case "bundle_build_started":
1180
+ this.progressBar.setCurrent(0);
1181
+ if (this.flags & ProgressFlags.FILE_CHANGED) this.progressBar.setTotal(0);
1196
1182
  this.flags |= ProgressFlags.BUILD_IN_PROGRESS;
1197
1183
  this.progressBar.start();
1198
1184
  this.renderManager.start();
@@ -1209,10 +1195,6 @@ var ProgressBarStatusReporter = class {
1209
1195
  break;
1210
1196
  case "transform":
1211
1197
  const { id, totalModules, transformedModules } = event;
1212
- if (this.flags & ProgressFlags.FILE_CHANGED) {
1213
- logger.debug("Transformed changed file", { id });
1214
- return;
1215
- }
1216
1198
  this.renderProgress(id, totalModules, transformedModules);
1217
1199
  break;
1218
1200
  case "watch_change":
@@ -1898,21 +1880,45 @@ function reporterPlugin(options) {
1898
1880
  let totalModules = initialTotalModules;
1899
1881
  let startedAt = 0;
1900
1882
  let transformedModules = 0;
1883
+ let cacheHitModules = 0;
1901
1884
  let unknownTotalModules = totalModules === 0;
1885
+ let rebuildPending = false;
1886
+ function getProcessedModules() {
1887
+ return transformedModules + cacheHitModules;
1888
+ }
1889
+ function reportProgress(id) {
1890
+ const processedModules = getProcessedModules();
1891
+ if (!unknownTotalModules && totalModules < processedModules) totalModules = processedModules;
1892
+ reporter?.update({
1893
+ type: "transform",
1894
+ id,
1895
+ totalModules: unknownTotalModules ? void 0 : totalModules,
1896
+ transformedModules: processedModules
1897
+ });
1898
+ }
1902
1899
  return {
1903
1900
  name: "rollipop:status",
1904
1901
  buildStart() {
1905
1902
  startedAt = performance.now();
1906
1903
  transformedModules = 0;
1904
+ cacheHitModules = 0;
1905
+ if (rebuildPending) {
1906
+ totalModules = 0;
1907
+ unknownTotalModules = false;
1908
+ rebuildPending = false;
1909
+ }
1907
1910
  reporter?.update({ type: "bundle_build_started" });
1908
1911
  },
1909
1912
  buildEnd(error) {
1910
1913
  const endedAt = performance.now();
1911
- if (transformedModules !== 0) totalModules = transformedModules;
1914
+ const processedModules = getProcessedModules();
1915
+ if (processedModules !== 0) totalModules = processedModules;
1912
1916
  unknownTotalModules = false;
1913
1917
  reporter?.update(error == null ? {
1914
1918
  type: "bundle_build_done",
1915
1919
  totalModules,
1920
+ transformedModules,
1921
+ cacheHitModules,
1916
1922
  duration: endedAt - startedAt
1917
1923
  } : {
1918
1924
  type: "bundle_build_failed",
@@ -1923,16 +1929,15 @@ function reporterPlugin(options) {
1923
1929
  order: "post",
1924
1930
  handler(_code, id) {
1925
1931
  ++transformedModules;
1926
- if (!unknownTotalModules && totalModules < transformedModules) totalModules = transformedModules;
1927
- reporter?.update({
1928
- type: "transform",
1929
- id,
1930
- totalModules: unknownTotalModules ? void 0 : totalModules,
1931
- transformedModules
1932
- });
1932
+ reportProgress(id);
1933
1933
  }
1934
1934
  },
1935
+ transformCacheHit(id) {
1936
+ ++cacheHitModules;
1937
+ reportProgress(id);
1938
+ },
1935
1939
  watchChange(id) {
1940
+ rebuildPending = true;
1936
1941
  reporter?.update({
1937
1942
  type: "watch_change",
1938
1943
  id
@@ -2347,7 +2352,7 @@ var FileSystemBundleStore = class {
2347
2352
  };
2348
2353
  //#endregion
2349
2354
  //#region src/server/bundler-pool.ts
2350
- var BundlerDevEngine = class extends node_events.default {
2355
+ var BundlerDevEngine = class {
2351
2356
  initializeHandle;
2352
2357
  isHmrEnabled;
2353
2358
  _id;
@@ -2356,24 +2361,14 @@ var BundlerDevEngine = class extends node_events.default {
2356
2361
  _devEngine = null;
2357
2362
  _state = "idle";
2358
2363
  _status = "idle";
2359
- constructor(options, config, buildOptions, onReporterEvent) {
2360
- super();
2364
+ constructor(options, config, buildOptions, eventBus) {
2361
2365
  this.options = options;
2362
2366
  this.config = config;
2363
2367
  this.buildOptions = buildOptions;
2364
- this.onReporterEvent = onReporterEvent;
2368
+ this.eventBus = eventBus;
2365
2369
  this._id = Bundler.createId(config, buildOptions);
2366
2370
  this.initializeHandle = taskHandler();
2367
2371
  this.isHmrEnabled = Boolean(buildOptions.dev && config.devMode.hmr);
2368
- this.on("buildStart", () => {
2369
- this._status = "building";
2370
- });
2371
- this.on("buildDone", () => {
2372
- this._status = "build-done";
2373
- });
2374
- this.on("buildFailed", () => {
2375
- this._status = "build-failed";
2376
- });
2377
2372
  this.initialize();
2378
2373
  }
2379
2374
  get id() {
@@ -2393,8 +2388,24 @@ var BundlerDevEngine = class extends node_events.default {
2393
2388
  async initialize() {
2394
2389
  if (this._state !== "idle" || this._devEngine != null) return this;
2395
2390
  this._state = "initializing";
2396
- const onEvent = this.onReporterEvent ? (event) => this.onReporterEvent(this._id, event) : void 0;
2397
- const devEngine = await Bundler.devEngine(bindReporter(this.config, this, onEvent), this.buildOptions, {
2391
+ const config = bindReporter(this.config, (event) => {
2392
+ switch (event.type) {
2393
+ case "bundle_build_started":
2394
+ this._status = "building";
2395
+ break;
2396
+ case "bundle_build_done":
2397
+ this._status = "build-done";
2398
+ break;
2399
+ case "bundle_build_failed":
2400
+ this._status = "build-failed";
2401
+ break;
2402
+ }
2403
+ this.eventBus.emit({
2404
+ ...event,
2405
+ bundlerId: this.id
2406
+ });
2407
+ });
2408
+ const devEngine = await Bundler.devEngine(config, this.buildOptions, {
2398
2409
  host: this.options.server.host,
2399
2410
  port: this.options.server.port,
2400
2411
  onHmrUpdates: (errorOrResult) => {
@@ -2404,17 +2415,25 @@ var BundlerDevEngine = class extends node_events.default {
2404
2415
  bundlerId: this.id,
2405
2416
  error: errorOrResult
2406
2417
  });
2407
- const normalizedError = normalizeRolldownError(errorOrResult);
2408
- this.config.reporter?.update({
2418
+ const event = {
2409
2419
  type: "bundle_build_failed",
2410
- error: normalizedError
2420
+ error: normalizeRolldownError(errorOrResult)
2421
+ };
2422
+ this._status = "build-failed";
2423
+ this.eventBus.emit({
2424
+ ...event,
2425
+ bundlerId: this.id
2411
2426
  });
2412
2427
  } else {
2413
2428
  logger$1.trace("Detected changed files", {
2414
2429
  bundlerId: this.id,
2415
2430
  changedFiles: errorOrResult.changedFiles
2416
2431
  });
2417
- this.emit("hmrUpdates", errorOrResult.updates);
2432
+ this.eventBus.emit({
2433
+ bundlerId: this.id,
2434
+ type: "hmr_updates",
2435
+ updates: errorOrResult.updates
2436
+ });
2418
2437
  }
2419
2438
  },
2420
2439
  onOutput: (errorOrResult) => {
@@ -2423,7 +2442,15 @@ var BundlerDevEngine = class extends node_events.default {
2423
2442
  logger$1.trace("onOutput", { bundlerId: this.id });
2424
2443
  logger$1.error(errorOrResult.message);
2425
2444
  this.buildFailedError = normalizedError;
2426
- this.emit("buildFailed", normalizedError);
2445
+ const event = {
2446
+ type: "bundle_build_failed",
2447
+ error: normalizedError
2448
+ };
2449
+ this._status = "build-failed";
2450
+ this.eventBus.emit({
2451
+ ...event,
2452
+ bundlerId: this.id
2453
+ });
2427
2454
  } else {
2428
2455
  const output = errorOrResult.output[0];
2429
2456
  this.updateBundleStore(output);
@@ -2459,16 +2486,13 @@ var BundlerDevEngine = class extends node_events.default {
2459
2486
  };
2460
2487
  var BundlerPool = class BundlerPool {
2461
2488
  static instances = /* @__PURE__ */ new Map();
2462
- constructor(config, resolvedServerOptions, onReporterEvent) {
2489
+ constructor(config, resolvedServerOptions, eventBus) {
2463
2490
  this.config = config;
2464
2491
  this.resolvedServerOptions = resolvedServerOptions;
2465
- this.onReporterEvent = onReporterEvent;
2466
- }
2467
- instanceKey(bundleName, buildOptions) {
2468
- return `${bundleName}-${Bundler.createId(this.config, buildOptions)}`;
2492
+ this.eventBus = eventBus;
2469
2493
  }
2470
2494
  get(bundleName, buildOptions) {
2471
- const key = this.instanceKey(getBaseBundleName(bundleName), buildOptions);
2495
+ const key = `${getBaseBundleName(bundleName)}-${Bundler.createId(this.config, buildOptions)}`;
2472
2496
  const instance = BundlerPool.instances.get(key);
2473
2497
  if (instance) return instance;
2474
2498
  else {
@@ -2476,16 +2500,14 @@ var BundlerPool = class BundlerPool {
2476
2500
  bundleName,
2477
2501
  key
2478
2502
  });
2479
- const instance = new BundlerDevEngine({ server: this.resolvedServerOptions }, this.config, buildOptions, this.onReporterEvent);
2503
+ const instance = new BundlerDevEngine({ server: this.resolvedServerOptions }, this.config, buildOptions, this.eventBus);
2480
2504
  logger$1.debug("Setting new bundler instance", { key });
2481
2505
  BundlerPool.instances.set(key, instance);
2482
2506
  return instance;
2483
2507
  }
2484
2508
  }
2485
2509
  /**
2486
- * Look up a cached bundler by its reporter-facing id (the same id carried
2487
- * in SSE events such as `bundle_build_done`). Returns `undefined` when no
2488
- * instance with that id has been created yet.
2510
+ * Look up a cached bundler by the id carried as `bundlerId` in events such as `bundle_build_done`. Returns `undefined` when no instance with that id has been created yet.
2489
2511
  */
2490
2512
  getInstanceById(id) {
2491
2513
  for (const instance of BundlerPool.instances.values()) if (instance.id === id) return instance;
@@ -2504,6 +2526,21 @@ function errorHandler(error, request, reply) {
2504
2526
  reply.status(500).send("Internal Server Error");
2505
2527
  }
2506
2528
  //#endregion
2529
+ //#region src/server/events/event-bus.ts
2530
+ var EventBus = class {
2531
+ listeners = /* @__PURE__ */ new Set();
2532
+ emit(event) {
2533
+ for (const listener of this.listeners) listener(event);
2534
+ }
2535
+ subscribe(listener) {
2536
+ this.listeners.add(listener);
2537
+ return () => {
2538
+ this.listeners.delete(listener);
2539
+ };
2540
+ }
2541
+ };
2542
+ var ServerEventBus = class extends EventBus {};
2543
+ //#endregion
2507
2544
  //#region src/utils/reset-cache.ts
2508
2545
  /**
2509
2546
  * Resolve the build cache directory for the given project root. The cache
@@ -2526,6 +2563,67 @@ function resetCache(projectRoot) {
2526
2563
  });
2527
2564
  }
2528
2565
  //#endregion
2566
+ //#region src/server/sse/adapter.ts
2567
+ function toSSEEvent(event) {
2568
+ switch (event.type) {
2569
+ case "client_log": return {
2570
+ type: "client_log",
2571
+ ...event.bundlerId != null ? { bundlerId: event.bundlerId } : {},
2572
+ data: event.data
2573
+ };
2574
+ case "device_connected": return {
2575
+ type: "device_connected",
2576
+ clientId: event.client.id
2577
+ };
2578
+ case "device_disconnected": return {
2579
+ type: "device_disconnected",
2580
+ clientId: event.client.id
2581
+ };
2582
+ case "server_ready":
2583
+ case "cache_reset": return event;
2584
+ case "bundle_build_started":
2585
+ case "bundle_build_done":
2586
+ case "bundle_build_failed":
2587
+ case "watch_change": return reporterEventToSSEEvent(event);
2588
+ case "hmr_updates":
2589
+ case "device_message":
2590
+ case "device_error":
2591
+ case "transform": return null;
2592
+ }
2593
+ }
2594
+ function reporterEventToSSEEvent(event) {
2595
+ switch (event.type) {
2596
+ case "bundle_build_started": return {
2597
+ type: "bundle_build_started",
2598
+ bundlerId: event.bundlerId
2599
+ };
2600
+ case "bundle_build_done": return {
2601
+ type: "bundle_build_done",
2602
+ bundlerId: event.bundlerId,
2603
+ totalModules: event.totalModules,
2604
+ transformedModules: event.transformedModules,
2605
+ cacheHitModules: event.cacheHitModules,
2606
+ duration: event.duration
2607
+ };
2608
+ case "bundle_build_failed": return {
2609
+ type: "bundle_build_failed",
2610
+ bundlerId: event.bundlerId,
2611
+ error: (0, strip_ansi.default)(event.error.message)
2612
+ };
2613
+ case "watch_change": return {
2614
+ type: "watch_change",
2615
+ bundlerId: event.bundlerId,
2616
+ file: event.id
2617
+ };
2618
+ case "client_log": return {
2619
+ type: "client_log",
2620
+ bundlerId: event.bundlerId,
2621
+ data: event.data
2622
+ };
2623
+ case "transform": return null;
2624
+ }
2625
+ }
2626
+ //#endregion
2529
2627
  //#region src/server/mcp/server.ts
2530
2628
  function createMcpServer(options) {
2531
2629
  const { projectRoot, eventBus } = options;
@@ -2546,11 +2644,14 @@ function createMcpServer(options) {
2546
2644
  });
2547
2645
  server.registerTool("get_build_events", {
2548
2646
  title: "Get Build Events",
2549
- description: "Subscribe to bundler events for a duration. Returns all events (build start/done/fail, watch changes, client logs, device connections) collected during the wait period.",
2647
+ description: "Subscribe to bundler events for a duration. Returns all events (build start/done/fail, watch changes, client logs, device connections) collected during the wait period. Bundler-scoped events include bundlerId.",
2550
2648
  inputSchema: { duration: zod.z.number().min(1e3).max(6e4).default(1e4).describe("How long to listen for events in milliseconds (1000-60000, default 10000)") }
2551
2649
  }, async ({ duration }) => {
2552
2650
  const events = [];
2553
- const unsubscribe = eventBus.collect(events);
2651
+ const unsubscribe = eventBus.subscribe((event) => {
2652
+ const sseEvent = toSSEEvent(event);
2653
+ if (sseEvent != null) events.push(sseEvent);
2654
+ });
2554
2655
  await new Promise((resolve) => setTimeout(resolve, duration));
2555
2656
  unsubscribe();
2556
2657
  if (events.length === 0) return { content: [{
@@ -2807,6 +2908,11 @@ const bundleRequestSchema = (0, json_schema_to_ts.asConst)({
2807
2908
  });
2808
2909
  new ajv.default().compile(bundleRequestSchema);
2809
2910
  //#endregion
2911
+ //#region src/server/events/types.ts
2912
+ function isBundlerEventForId(event, bundlerId) {
2913
+ return "bundlerId" in event && event.bundlerId === bundlerId;
2914
+ }
2915
+ //#endregion
2810
2916
  //#region src/server/middlewares/serve-bundle.ts
2811
2917
  const routeParamSchema = (0, json_schema_to_ts.asConst)({
2812
2918
  type: "object",
@@ -2818,7 +2924,7 @@ function withGetBundleErrorHandler(reply, task) {
2818
2924
  });
2819
2925
  }
2820
2926
  const plugin$2 = (0, fastify_plugin.default)((fastify, options) => {
2821
- const { getBundler } = options;
2927
+ const { eventBus, getBundler } = options;
2822
2928
  const getBundleOptions = (buildOptions) => {
2823
2929
  return {
2824
2930
  platform: buildOptions.platform,
@@ -2842,11 +2948,10 @@ const plugin$2 = (0, fastify_plugin.default)((fastify, options) => {
2842
2948
  const bundler = getBundler(params.name, buildOptions);
2843
2949
  if (accept?.includes("multipart/mixed") ?? false) {
2844
2950
  const bundleResponse = new BundleResponse(reply);
2845
- const transformHandler = (_id, totalModules = 0, transformedModules) => {
2846
- bundleResponse.writeBundleState(transformedModules, totalModules);
2847
- };
2848
- bundler.on("transform", transformHandler);
2849
- await bundler.getBundle().then((bundle) => bundleResponse.endWithBundle(bundle.code)).catch((error) => bundleResponse.endWithError(error)).finally(() => bundler.off("transform", transformHandler));
2951
+ const unsubscribe = eventBus.subscribe((event) => {
2952
+ if (isBundlerEventForId(event, bundler.id) && event.type === "transform") bundleResponse.writeBundleState(event.transformedModules, event.totalModules ?? 0);
2953
+ });
2954
+ await bundler.getBundle().then((bundle) => bundleResponse.endWithBundle(bundle.code)).catch((error) => bundleResponse.endWithError(error)).finally(unsubscribe);
2850
2955
  } else {
2851
2956
  this.log.debug(`client is not support multipart/mixed content: ${accept ?? "<empty>"}`);
2852
2957
  const code = (await withGetBundleErrorHandler(reply, bundler.getBundle())).code;
@@ -2874,7 +2979,7 @@ const plugin$2 = (0, fastify_plugin.default)((fastify, options) => {
2874
2979
  }, { name: "serve-bundle" });
2875
2980
  //#endregion
2876
2981
  //#region src/server/middlewares/sse.ts
2877
- const plugin$1 = (0, fastify_plugin.default)((fastify, { eventBus }) => {
2982
+ const plugin$1 = (0, fastify_plugin.default)((fastify, { publisher }) => {
2878
2983
  fastify.get("/sse/events", (request, reply) => {
2879
2984
  const res = reply.raw;
2880
2985
  res.writeHead(200, {
@@ -2885,8 +2990,8 @@ const plugin$1 = (0, fastify_plugin.default)((fastify, { eventBus }) => {
2885
2990
  });
2886
2991
  request.raw.socket.setNoDelay(true);
2887
2992
  res.write(":ok\n\n");
2888
- eventBus.addClient(res);
2889
- request.raw.on("close", () => eventBus.removeClient(res));
2993
+ publisher.addClient(res);
2994
+ request.raw.on("close", () => publisher.removeClient(res));
2890
2995
  });
2891
2996
  }, { name: "sse" });
2892
2997
  //#endregion
@@ -3062,14 +3167,12 @@ function printSymbolicateResult(rawStackFrame, symbolicateResult) {
3062
3167
  }
3063
3168
  //#endregion
3064
3169
  //#region src/server/sse/event-bus.ts
3065
- var SSEEventBus = class {
3170
+ var SSEEventPublisher = class {
3066
3171
  clients = /* @__PURE__ */ new Set();
3067
- listeners = /* @__PURE__ */ new Set();
3068
- emit(event) {
3172
+ publish(event) {
3069
3173
  const data = JSON.stringify(event);
3070
3174
  const message = `event: ${event.type}\ndata: ${data}\n\n`;
3071
3175
  for (const client of this.clients) if (!client.closed) client.write(message);
3072
- for (const listener of this.listeners) listener(event);
3073
3176
  }
3074
3177
  /**
3075
3178
  * Subscribe an SSE HTTP response client.
@@ -3083,51 +3186,11 @@ var SSEEventBus = class {
3083
3186
  removeClient(res) {
3084
3187
  this.clients.delete(res);
3085
3188
  }
3086
- /**
3087
- * Subscribe a listener that collects events into the given array.
3088
- * Returns an unsubscribe function.
3089
- */
3090
- collect(collector) {
3091
- const listener = (event) => collector.push(event);
3092
- this.listeners.add(listener);
3093
- return () => this.listeners.delete(listener);
3094
- }
3095
3189
  get clientCount() {
3096
3190
  return this.clients.size;
3097
3191
  }
3098
3192
  };
3099
3193
  //#endregion
3100
- //#region src/server/sse/reporter.ts
3101
- function toSSEEvent(id, event) {
3102
- switch (event.type) {
3103
- case "bundle_build_started": return {
3104
- type: "bundle_build_started",
3105
- id
3106
- };
3107
- case "bundle_build_done": return {
3108
- type: "bundle_build_done",
3109
- id,
3110
- totalModules: event.totalModules,
3111
- duration: event.duration
3112
- };
3113
- case "bundle_build_failed": return {
3114
- type: "bundle_build_failed",
3115
- id,
3116
- error: (0, strip_ansi.default)(event.error.message)
3117
- };
3118
- case "watch_change": return {
3119
- type: "watch_change",
3120
- id,
3121
- file: event.id
3122
- };
3123
- case "client_log": return {
3124
- type: "client_log",
3125
- data: event.data
3126
- };
3127
- case "transform": return null;
3128
- }
3129
- }
3130
- //#endregion
3131
3194
  //#region src/server/wss/server.ts
3132
3195
  var WebSocketServer = class extends node_events.default {
3133
3196
  clientId = 0;
@@ -3196,13 +3259,13 @@ function getWebSocketUpgradeHandler(websocketEndpoints) {
3196
3259
  //#region src/server/wss/hmr-server.ts
3197
3260
  var HMRServer = class extends WebSocketServer {
3198
3261
  bundlerPool;
3199
- reportEvent;
3262
+ eventBus;
3200
3263
  instances = /* @__PURE__ */ new Map();
3201
3264
  bindings = /* @__PURE__ */ new Map();
3202
- constructor({ bundlerPool, reportEvent }) {
3265
+ constructor({ bundlerPool, eventBus }) {
3203
3266
  super("hmr", { noServer: true });
3204
3267
  this.bundlerPool = bundlerPool;
3205
- this.reportEvent = reportEvent;
3268
+ this.eventBus = eventBus;
3206
3269
  }
3207
3270
  parseClientMessage(data) {
3208
3271
  const parsedData = JSON.parse(this.rawDataToString(data));
@@ -3229,33 +3292,34 @@ var HMRServer = class extends WebSocketServer {
3229
3292
  }
3230
3293
  bindEvents(client, instance) {
3231
3294
  if (this.bindings.get(client.id) == null) {
3232
- const handleHmrUpdates = (updates) => {
3233
- this.handleUpdates(client, updates);
3234
- };
3235
- const handleWatchChange = () => {
3236
- this.send(client, JSON.stringify({ type: "hmr:update-start" }));
3237
- };
3238
- const handleBuildFailed = (error) => {
3239
- this.send(client, JSON.stringify({
3240
- type: "hmr:error",
3241
- payload: {
3242
- type: "BuildError",
3243
- errors: [{ description: error.message }],
3244
- message: error.message
3245
- }
3246
- }));
3247
- };
3248
- instance.addListener("hmrUpdates", handleHmrUpdates);
3249
- instance.addListener("watchChange", handleWatchChange);
3250
- instance.addListener("buildFailed", handleBuildFailed);
3251
- this.bindings.set(client.id, {
3252
- hmrUpdates: handleHmrUpdates,
3253
- watchChange: handleWatchChange,
3254
- buildFailed: handleBuildFailed
3295
+ const unsubscribe = this.eventBus.subscribe((event) => {
3296
+ if (!isBundlerEventForId(event, instance.id)) return;
3297
+ switch (event.type) {
3298
+ case "hmr_updates":
3299
+ this.handleUpdates(client, event.updates);
3300
+ break;
3301
+ case "watch_change":
3302
+ this.send(client, JSON.stringify({ type: "hmr:update-start" }));
3303
+ break;
3304
+ case "bundle_build_failed":
3305
+ this.sendBuildFailed(client, event.error);
3306
+ break;
3307
+ }
3255
3308
  });
3309
+ this.bindings.set(client.id, { unsubscribe });
3256
3310
  this.logger.trace(`HMR event binding established (clientId: ${client.id})`);
3257
3311
  }
3258
3312
  }
3313
+ sendBuildFailed(client, error) {
3314
+ this.send(client, JSON.stringify({
3315
+ type: "hmr:error",
3316
+ payload: {
3317
+ type: "BuildError",
3318
+ errors: [{ description: error.message }],
3319
+ message: error.message
3320
+ }
3321
+ }));
3322
+ }
3259
3323
  async handleModuleRegistered(client, modules) {
3260
3324
  try {
3261
3325
  const instance = this.instances.get(client.id);
@@ -3322,11 +3386,7 @@ var HMRServer = class extends WebSocketServer {
3322
3386
  this.logger.trace(`HMR client cleanup (clientId: ${client.id})`);
3323
3387
  const binding = this.bindings.get(client.id);
3324
3388
  const instance = this.instances.get(client.id);
3325
- if (binding != null && instance != null) {
3326
- instance.removeListener("hmrUpdates", binding.hmrUpdates);
3327
- instance.removeListener("watchChange", binding.watchChange);
3328
- instance.removeListener("buildFailed", binding.buildFailed);
3329
- }
3389
+ if (binding != null) binding.unsubscribe();
3330
3390
  if (instance != null) try {
3331
3391
  instance.devEngine.removeClient(String(client.id));
3332
3392
  } catch (error) {
@@ -3373,13 +3433,16 @@ var HMRServer = class extends WebSocketServer {
3373
3433
  case "hmr:invalidate":
3374
3434
  this.handleInvalidate(client, message.moduleId);
3375
3435
  break;
3376
- case "hmr:log":
3377
- this.reportEvent({
3436
+ case "hmr:log": {
3437
+ const instance = this.instances.get(client.id);
3438
+ this.eventBus.emit({
3378
3439
  type: "client_log",
3440
+ ...instance != null ? { bundlerId: instance.id } : {},
3379
3441
  level: message.level,
3380
3442
  data: message.data
3381
3443
  });
3382
3444
  break;
3445
+ }
3383
3446
  }
3384
3447
  }
3385
3448
  onConnection(client) {
@@ -3420,22 +3483,58 @@ async function createDevServer(config, options) {
3420
3483
  loggerInstance: new DevServerLogger(),
3421
3484
  disableRequestLogging: true
3422
3485
  });
3423
- const sseEventBus = new SSEEventBus();
3424
- const bundlerPool = new BundlerPool(config, {
3425
- host,
3426
- port
3427
- }, (id, event) => {
3428
- const sseEvent = toSSEEvent(id, event);
3429
- if (sseEvent) sseEventBus.emit(sseEvent);
3486
+ const eventBus = new ServerEventBus();
3487
+ const ssePublisher = new SSEEventPublisher();
3488
+ const reporter = config.reporter;
3489
+ eventBus.subscribe((event) => {
3490
+ const sseEvent = toSSEEvent(event);
3491
+ if (sseEvent != null) ssePublisher.publish(sseEvent);
3430
3492
  });
3431
- const getBundler = (bundleName, buildOptions) => {
3432
- return bundlerPool.get(bundleName, (0, es_toolkit.merge)(options?.buildOptions ?? {}, buildOptions));
3433
- };
3434
3493
  const { middleware: communityMiddleware, websocketEndpoints: communityWebsocketEndpoints, messageSocketEndpoint: { server: messageServer, broadcast }, eventsSocketEndpoint: { server: eventsServer, reportEvent } } = (0, _react_native_community_cli_server_api.createDevServerMiddleware)({
3435
3494
  port,
3436
3495
  host,
3437
3496
  watchFolders: []
3438
3497
  });
3498
+ eventBus.subscribe((event) => {
3499
+ switch (event.type) {
3500
+ case "bundle_build_started":
3501
+ case "bundle_build_done":
3502
+ case "bundle_build_failed":
3503
+ case "transform":
3504
+ case "watch_change":
3505
+ reporter?.update(event);
3506
+ break;
3507
+ case "client_log":
3508
+ reportEvent?.(event);
3509
+ reporter?.update(event);
3510
+ break;
3511
+ case "device_connected":
3512
+ emitter.emit("device.connected", { client: event.client });
3513
+ break;
3514
+ case "device_message":
3515
+ emitter.emit("device.message", {
3516
+ client: event.client,
3517
+ data: event.data
3518
+ });
3519
+ break;
3520
+ case "device_error":
3521
+ emitter.emit("device.error", {
3522
+ client: event.client,
3523
+ error: event.error
3524
+ });
3525
+ break;
3526
+ case "device_disconnected":
3527
+ emitter.emit("device.disconnected", { client: event.client });
3528
+ break;
3529
+ }
3530
+ });
3531
+ const bundlerPool = new BundlerPool(config, {
3532
+ host,
3533
+ port
3534
+ }, eventBus);
3535
+ const getBundler = (bundleName, buildOptions) => {
3536
+ return bundlerPool.get(bundleName, (0, es_toolkit.merge)(options?.buildOptions ?? {}, buildOptions));
3537
+ };
3439
3538
  const { middleware: devMiddleware, websocketEndpoints } = (0, _react_native_dev_middleware.createDevMiddleware)({
3440
3539
  serverBaseUrl,
3441
3540
  logger: {
@@ -3453,29 +3552,22 @@ async function createDevServer(config, options) {
3453
3552
  });
3454
3553
  const hmrServer = new HMRServer({
3455
3554
  bundlerPool,
3456
- reportEvent: (event) => {
3457
- reportEvent?.(event);
3458
- config.reporter?.update(event);
3459
- }
3460
- }).on("connection", (client) => {
3461
- emitter.emit("device.connected", { client });
3462
- sseEventBus.emit({
3463
- type: "device_connected",
3464
- clientId: client.id
3465
- });
3466
- }).on("message", (client, data) => emitter.emit("device.message", {
3555
+ eventBus
3556
+ }).on("connection", (client) => eventBus.emit({
3557
+ type: "device_connected",
3558
+ client
3559
+ })).on("message", (client, data) => eventBus.emit({
3560
+ type: "device_message",
3467
3561
  client,
3468
3562
  data
3469
- })).on("error", (client, error) => emitter.emit("device.error", {
3563
+ })).on("error", (client, error) => eventBus.emit({
3564
+ type: "device_error",
3470
3565
  client,
3471
3566
  error
3472
- })).on("close", (client) => {
3473
- emitter.emit("device.disconnected", { client });
3474
- sseEventBus.emit({
3475
- type: "device_disconnected",
3476
- clientId: client.id
3477
- });
3478
- });
3567
+ })).on("close", (client) => eventBus.emit({
3568
+ type: "device_disconnected",
3569
+ client
3570
+ }));
3479
3571
  await fastify$1.register(import("@fastify/middie"));
3480
3572
  const devServer = {
3481
3573
  ...emitter,
@@ -3500,13 +3592,16 @@ async function createDevServer(config, options) {
3500
3592
  })
3501
3593
  };
3502
3594
  const { invokePostConfigureServer } = await invokeConfigureServer(devServer, config.plugins ?? []);
3503
- fastify$1.use(requestLogger).use(communityMiddleware).use(devMiddleware).register(plugin$1, { eventBus: sseEventBus }).register(plugin$4, {
3595
+ fastify$1.use(requestLogger).use(communityMiddleware).use(devMiddleware).register(plugin$1, { publisher: ssePublisher }).register(plugin$4, {
3504
3596
  projectRoot,
3505
- eventBus: sseEventBus
3597
+ eventBus
3506
3598
  }).register(plugin$5, { bundlerPool }).register(plugin$6, {
3507
3599
  projectRoot,
3508
- eventBus: sseEventBus
3509
- }).register(plugin, { getBundler }).register(plugin$2, { getBundler }).register(plugin$3, {
3600
+ eventBus
3601
+ }).register(plugin, { getBundler }).register(plugin$2, {
3602
+ eventBus,
3603
+ getBundler
3604
+ }).register(plugin$3, {
3510
3605
  projectRoot,
3511
3606
  host,
3512
3607
  port,
@@ -3519,7 +3614,7 @@ async function createDevServer(config, options) {
3519
3614
  "/hot": hmrServer.server
3520
3615
  }));
3521
3616
  await invokePostConfigureServer();
3522
- sseEventBus.emit({
3617
+ eventBus.emit({
3523
3618
  type: "server_ready",
3524
3619
  host,
3525
3620
  port
@@ -3568,6 +3663,7 @@ function getAgentGuide(baseUrl = defaultBaseUrl) {
3568
3663
  " Event format:",
3569
3664
  " event: <event_type>",
3570
3665
  " data: <json_payload>",
3666
+ " bundler-scoped events include bundlerId",
3571
3667
  "",
3572
3668
  " Useful event types:",
3573
3669
  " bundle_build_started, bundle_build_done, bundle_build_failed",
@@ -3696,6 +3792,7 @@ function mergeConfig(baseConfig, ...overrideConfigs) {
3696
3792
  //#endregion
3697
3793
  //#region src/config/load-config.ts
3698
3794
  const CONFIG_FILE_NAME = "rollipop";
3795
+ const INTERNAL_PLUGIN_HOOKS = ["transformCacheHit"];
3699
3796
  async function loadConfig(options = {}) {
3700
3797
  const { cwd = process.cwd(), configFile, mode, context = {} } = options;
3701
3798
  const defaultConfig = await getDefaultConfig(cwd, mode);
@@ -3730,7 +3827,12 @@ async function flattenPluginOption(pluginOption) {
3730
3827
  const awaitedPluginOption = await pluginOption;
3731
3828
  if (Array.isArray(awaitedPluginOption)) return (await Promise.all(awaitedPluginOption.map(flattenPluginOption))).flat();
3732
3829
  if (awaitedPluginOption == null || awaitedPluginOption === false) return [];
3733
- return [awaitedPluginOption];
3830
+ return [stripInternalPluginHooks(awaitedPluginOption)];
3831
+ }
3832
+ function stripInternalPluginHooks(plugin) {
3833
+ const maybeInternalPlugin = plugin;
3834
+ if (!INTERNAL_PLUGIN_HOOKS.some((hook) => hook in maybeInternalPlugin)) return plugin;
3835
+ return (0, es_toolkit.omit)(maybeInternalPlugin, INTERNAL_PLUGIN_HOOKS);
3734
3836
  }
3735
3837
  async function resolvePluginConfig(baseConfig, plugins) {
3736
3838
  let mergedConfig = (0, es_toolkit.omit)(baseConfig, ["plugins"]);
@@ -3900,6 +4002,7 @@ const action = async function(options) {
3900
4002
  dev: options.dev,
3901
4003
  minify: options.minify,
3902
4004
  cache: options.cache,
4005
+ ...options.sourcemapOutput ? { sourcemap: true } : {},
3903
4006
  outfile: options.bundleOutput,
3904
4007
  sourcemapOutfile: options.sourcemapOutput,
3905
4008
  assetsDir: options.assetsDest