rollipop 1.0.0-beta.1 → 1.0.0-beta.3

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 (45) hide show
  1. package/README.md +4 -0
  2. package/dist/config/defaults.js +6 -4
  3. package/dist/config/types.d.ts +3 -2
  4. package/dist/constants.js +1 -1
  5. package/dist/core/plugins/babel-plugin.js +1 -1
  6. package/dist/core/plugins/types.d.ts +2 -1
  7. package/dist/core/rolldown.js +3 -10
  8. package/dist/events/types.d.ts +2 -1
  9. package/dist/hmr-runtime.iife.js +302 -195
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.js +2 -1
  12. package/dist/internal/react-native/legacy.js +14 -0
  13. package/dist/internal/react-native/polyfills.js +28 -0
  14. package/dist/internal/react-native/public-assets.js +14 -0
  15. package/dist/internal/react-native/public.js +14 -0
  16. package/dist/internal/react-native/runtime.js +25 -0
  17. package/dist/internal/react-native.js +2 -41
  18. package/dist/node/commands/agent/index.js +1 -2
  19. package/dist/node/commands/bundle/command.js +8 -0
  20. package/dist/node/commands/bundle/index.js +1 -2
  21. package/dist/node/commands/start/index.js +1 -2
  22. package/dist/package.js +1 -1
  23. package/dist/rolldown-runtime-DXE2a-Yu.js +27 -0
  24. package/dist/runtime.d.ts +1 -1
  25. package/dist/runtime.js +1 -1
  26. package/dist/server/bundle.d.ts +2 -1
  27. package/dist/server/create-dev-server.js +1 -1
  28. package/dist/server/devframe/events.js +4 -1
  29. package/dist/server/devframe/index.js +31 -8
  30. package/dist/server/devframe/setup.js +4 -1
  31. package/dist/server/hot-update-store.d.ts +7 -0
  32. package/dist/server/hot-update-store.js +24 -2
  33. package/dist/server/symbolicate.js +12 -6
  34. package/dist/server/types.d.ts +5 -0
  35. package/dist/storage/file-storage.js +1 -1
  36. package/dist/utils/transform.js +2 -1
  37. package/dist/utils/worklets.d.ts +7 -0
  38. package/dist/utils/worklets.js +32 -0
  39. package/package.json +26 -23
  40. package/skills/configuration.md +1 -1
  41. package/skills/plugins.md +1 -1
  42. package/src/runtime/__tests__/hmr-runtime.spec.ts +171 -72
  43. package/src/runtime/hmr-client.ts +1 -1
  44. package/src/runtime/hmr-runtime.ts +76 -0
  45. package/dist/rolldown-runtime-BHXq-rbM.js +0 -24
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ import { resetCache } from "./utils/reset-cache.js";
19
19
  import { Bundler } from "./core/bundler.js";
20
20
  import { assets_d_exports } from "./core/assets.js";
21
21
  import { LoadEnvOptions, loadEnv } from "./core/env.js";
22
+ import { resolveWorkletsConfig } from "./utils/worklets.js";
22
23
  import { constants_d_exports } from "./constants.js";
23
24
  import { HMRClientLogLevel, HMRClientMessage, HMRContext, HMRCustomHandler, HMRCustomMessage, HMRServerError, HMRServerMessage } from "./types/hmr.js";
24
25
  import { cli_d_exports } from "./node/cli.js";
@@ -29,4 +30,4 @@ import { OutputChunk } from "@rollipop/rolldown";
29
30
  export declare function runBuild(config: ResolvedConfig, options: BuildOptions): Promise<OutputChunk>;
30
31
  export declare function runServer(config: ResolvedConfig, options: ServerOptions): Promise<DevServer>;
31
32
  //#endregion
32
- export { type AliasConfig, type AnalyzerConfig, assets_d_exports as AssetUtils, type AsyncResult, type BabelTransformConfig, type BuildDiagnosticLog, type BuildOptions, type BuildType, type BundleDetails, Bundler, type BundlerContext, type BundlerState, type ChangeEvent, type Config, constants_d_exports as Constants, DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH, type DeepRequired, DefaultConfig, DefineConfigContext, type DevConfig, type DevEngine, type DevEngineOptions, type DevServer, type DevServerContext, type DevServerEvents, type DevToolsPluginOptions, DynamicUserConfig, type ExperimentalConfig, type ExtractObject, type FastifyInstance, type FlowConfig, type FlowConfig as RollipopReactNativeFlowConfig, type FormattedError, type HMRClientLogLevel, type HMRClientMessage, type HMRContext, type HMRCustomHandler, type HMRCustomMessage, type HMRServerError, type HMRServerMessage, type HmrConfig, type HotUpdateOptions, InteractiveCommand, InteractiveCommandContext, InteractiveModeOptions, InternalConfig, type JsxOptions, LoadConfigOptions, LoadEnvOptions, type MaybePromise, type Middlewares, type NullValue, type OptimizationConfig, type OutputConfig, type PackageJson, type Plugin, type PluginConfig, PluginFlattenConfig, type PluginOption, type PluginWithHotUpdate, type Polyfill, type PolyfillOptions, type PolyfillType, type PolyfillWithCode, type PolyfillWithPath, type ReactNativeConfig, type ReportableEvent, type Reporter, type ResolveConfig, ResolvedConfig, type RolldownOptions, type RolldownOptionsConfig, type RolldownOptionsContext, type RolldownOptionsFunction, type RollipopDevToolsNodeContext, type SwcConfig as RollipopReactNativeSwcConfig, type SwcConfig, type WorkletsConfig as RollipopReactNativeWorkletsConfig, type WorkletsConfig, type ServerOptions, type SwcTransformConfig, type TransformConfig, type TransformRule, UserConfig, type WatcherConfig, cli_d_exports as cli, createCommand, createDevServer, createReactNativeCliCommand, defineConfig, flattenPluginOption, getDefaultConfig, invokeConfigResolved, loadConfig, loadEnv, mergeConfig, index_d_exports as plugins, resetCache, resolvePluginConfig, rolldown, rolldownExperimental, setupInteractiveMode };
33
+ export { type AliasConfig, type AnalyzerConfig, assets_d_exports as AssetUtils, type AsyncResult, type BabelTransformConfig, type BuildDiagnosticLog, type BuildOptions, type BuildType, type BundleDetails, Bundler, type BundlerContext, type BundlerState, type ChangeEvent, type Config, constants_d_exports as Constants, DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH, type DeepRequired, DefaultConfig, DefineConfigContext, type DevConfig, type DevEngine, type DevEngineOptions, type DevServer, type DevServerContext, type DevServerEvents, type DevToolsPluginOptions, DynamicUserConfig, type ExperimentalConfig, type ExtractObject, type FastifyInstance, type FlowConfig, type FlowConfig as RollipopReactNativeFlowConfig, type FormattedError, type HMRClientLogLevel, type HMRClientMessage, type HMRContext, type HMRCustomHandler, type HMRCustomMessage, type HMRServerError, type HMRServerMessage, type HmrConfig, type HotUpdateOptions, InteractiveCommand, InteractiveCommandContext, InteractiveModeOptions, InternalConfig, type JsxOptions, LoadConfigOptions, LoadEnvOptions, type MaybePromise, type Middlewares, type NullValue, type OptimizationConfig, type OutputConfig, type PackageJson, type Plugin, type PluginConfig, PluginFlattenConfig, type PluginOption, type PluginWithHotUpdate, type Polyfill, type PolyfillOptions, type PolyfillType, type PolyfillWithCode, type PolyfillWithPath, type ReactNativeConfig, type ReportableEvent, type Reporter, type ResolveConfig, ResolvedConfig, type RolldownOptions, type RolldownOptionsConfig, type RolldownOptionsContext, type RolldownOptionsFunction, type RollipopDevToolsNodeContext, type SwcConfig as RollipopReactNativeSwcConfig, type SwcConfig, type WorkletsConfig as RollipopReactNativeWorkletsConfig, type WorkletsConfig, type ServerOptions, type SwcTransformConfig, type TransformConfig, type TransformRule, UserConfig, type WatcherConfig, cli_d_exports as cli, createCommand, createDevServer, createReactNativeCliCommand, defineConfig, flattenPluginOption, getDefaultConfig, invokeConfigResolved, loadConfig, loadEnv, mergeConfig, index_d_exports as plugins, resetCache, resolvePluginConfig, resolveWorkletsConfig, rolldown, rolldownExperimental, setupInteractiveMode };
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { mergeConfig } from "./config/merge-config.js";
5
5
  import { flattenPluginOption, invokeConfigResolved, loadConfig, resolvePluginConfig } from "./config/load-config.js";
6
6
  import "./config/index.js";
7
7
  import { resetCache } from "./utils/reset-cache.js";
8
+ import { resolveWorkletsConfig } from "./utils/worklets.js";
8
9
  import { loadEnv } from "./core/env.js";
9
10
  import { DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH } from "./server/constants.js";
10
11
  import { createDevServer } from "./server/index.js";
@@ -26,4 +27,4 @@ async function runServer(config, options) {
26
27
  return runServer(config, options);
27
28
  }
28
29
  //#endregion
29
- export { assets_exports as AssetUtils, Bundler, constants_exports as Constants, DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH, cli_exports as cli, createCommand, createDevServer, createReactNativeCliCommand, defineConfig, flattenPluginOption, getDefaultConfig, invokeConfigResolved, loadConfig, loadEnv, mergeConfig, plugins_exports as plugins, resetCache, resolvePluginConfig, rolldown, rolldownExperimental, runBuild, runServer, setupInteractiveMode };
30
+ export { assets_exports as AssetUtils, Bundler, constants_exports as Constants, DEFAULT_HOST, DEFAULT_PORT, DEV_SERVER_ASSET_PATH, cli_exports as cli, createCommand, createDevServer, createReactNativeCliCommand, defineConfig, flattenPluginOption, getDefaultConfig, invokeConfigResolved, loadConfig, loadEnv, mergeConfig, plugins_exports as plugins, resetCache, resolvePluginConfig, resolveWorkletsConfig, rolldown, rolldownExperimental, runBuild, runServer, setupInteractiveMode };
@@ -0,0 +1,14 @@
1
+ import { resolvePolyfillScriptPaths } from "./polyfills.js";
2
+ //#region src/internal/react-native/legacy.ts
3
+ const legacyRuntime = {
4
+ range: "<0.87.0-0",
5
+ resolve(context) {
6
+ return {
7
+ prelude: [context.require.resolve("./Libraries/Core/InitializeCore")],
8
+ polyfills: resolvePolyfillScriptPaths(context),
9
+ assetRegistryPath: "react-native/Libraries/Image/AssetRegistry.js"
10
+ };
11
+ }
12
+ };
13
+ //#endregion
14
+ export { legacyRuntime };
@@ -0,0 +1,28 @@
1
+ import { resolvePackagePath } from "../../utils/node-resolve.js";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+ //#region src/internal/react-native/polyfills.ts
5
+ function resolvePolyfillScriptPaths({ projectRoot, reactNativePath, require }) {
6
+ const polyfillPath = resolveOptional(() => require.resolve("@react-native/js-polyfills", { paths: [reactNativePath, projectRoot] }));
7
+ if (polyfillPath) return require(polyfillPath)();
8
+ let metroConfigPath;
9
+ try {
10
+ metroConfigPath = resolvePackagePath(projectRoot, "@react-native/metro-config");
11
+ } catch {}
12
+ if (metroConfigPath) {
13
+ const requireFromMetroConfig = createRequire(path.join(metroConfigPath, "package.json"));
14
+ const metroPolyfillPath = resolveOptional(() => requireFromMetroConfig.resolve("@react-native/js-polyfills"));
15
+ if (metroPolyfillPath) return requireFromMetroConfig(metroPolyfillPath)();
16
+ }
17
+ return require("./rn-get-polyfills")();
18
+ }
19
+ function resolveOptional(resolve) {
20
+ try {
21
+ return resolve();
22
+ } catch (error) {
23
+ if (error instanceof Error && "code" in error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED")) return;
24
+ throw error;
25
+ }
26
+ }
27
+ //#endregion
28
+ export { resolvePolyfillScriptPaths };
@@ -0,0 +1,14 @@
1
+ import { resolvePolyfillScriptPaths } from "./polyfills.js";
2
+ //#region src/internal/react-native/public-assets.ts
3
+ const publicAssetsRuntime = {
4
+ range: ">=0.87.0-0 <0.88.0-0",
5
+ resolve(context) {
6
+ return {
7
+ prelude: [context.require.resolve("./Libraries/Core/InitializeCore")],
8
+ polyfills: resolvePolyfillScriptPaths(context),
9
+ assetRegistryPath: "react-native/asset-registry"
10
+ };
11
+ }
12
+ };
13
+ //#endregion
14
+ export { publicAssetsRuntime };
@@ -0,0 +1,14 @@
1
+ import { resolvePolyfillScriptPaths } from "./polyfills.js";
2
+ //#region src/internal/react-native/public.ts
3
+ const publicRuntime = {
4
+ range: ">=0.88.0-0",
5
+ resolve(context) {
6
+ return {
7
+ prelude: [context.require.resolve("react-native/setup-env")],
8
+ polyfills: resolvePolyfillScriptPaths(context),
9
+ assetRegistryPath: "react-native/asset-registry"
10
+ };
11
+ }
12
+ };
13
+ //#endregion
14
+ export { publicRuntime };
@@ -0,0 +1,25 @@
1
+ import { legacyRuntime } from "./legacy.js";
2
+ import { publicRuntime } from "./public.js";
3
+ import { publicAssetsRuntime } from "./public-assets.js";
4
+ import { createRequire } from "node:module";
5
+ import path from "node:path";
6
+ import { satisfies } from "semver";
7
+ //#region src/internal/react-native/runtime.ts
8
+ const strategies = [
9
+ publicRuntime,
10
+ publicAssetsRuntime,
11
+ legacyRuntime
12
+ ];
13
+ function resolveReactNativeRuntime(projectRoot, reactNativePath) {
14
+ const require = createRequire(path.join(reactNativePath, "package.json"));
15
+ const { version } = require("./package.json");
16
+ const strategy = strategies.find(({ range }) => satisfies(version, range, { includePrerelease: true }));
17
+ if (!strategy) throw new Error(`Unsupported React Native version: ${version}`);
18
+ return strategy.resolve({
19
+ projectRoot,
20
+ reactNativePath,
21
+ require
22
+ });
23
+ }
24
+ //#endregion
25
+ export { resolveReactNativeRuntime };
@@ -1,46 +1,7 @@
1
1
  import { asLiteral } from "../common/code.js";
2
- import { resolvePackagePath } from "../utils/node-resolve.js";
3
- import { createRequire } from "node:module";
4
- import path from "node:path";
2
+ import { resolveReactNativeRuntime } from "./react-native/runtime.js";
5
3
  import { isNotNil } from "es-toolkit";
6
4
  //#region src/internal/react-native.ts
7
- const ASSET_REGISTRY_PATH = "react-native/asset-registry";
8
- const LEGACY_ASSET_REGISTRY_PATH = "react-native/Libraries/Image/AssetRegistry.js";
9
- const require = createRequire(import.meta.url);
10
- function resolveInitializeCorePath(basePath) {
11
- return resolveOptional("react-native/setup-env", [basePath]) ?? require.resolve("react-native/Libraries/Core/InitializeCore", { paths: [basePath] });
12
- }
13
- function resolveAssetRegistryPath(basePath) {
14
- return resolveOptional(ASSET_REGISTRY_PATH, [basePath]) ? ASSET_REGISTRY_PATH : LEGACY_ASSET_REGISTRY_PATH;
15
- }
16
- function resolvePolyfillScriptPaths(basePath, reactNativePath) {
17
- const polyfillPath = resolveOptional("@react-native/js-polyfills", [reactNativePath, basePath]);
18
- if (polyfillPath) return loadPolyfillScriptPaths(polyfillPath);
19
- let metroConfigPath;
20
- try {
21
- metroConfigPath = resolvePackagePath(basePath, "@react-native/metro-config");
22
- } catch {}
23
- if (metroConfigPath) {
24
- const requireFromMetroConfig = createRequire(path.join(metroConfigPath, "package.json"));
25
- const metroPolyfillPath = resolveOptionalWith(() => requireFromMetroConfig.resolve("@react-native/js-polyfills"));
26
- if (metroPolyfillPath) return loadPolyfillScriptPaths(metroPolyfillPath, requireFromMetroConfig);
27
- }
28
- return loadPolyfillScriptPaths(require.resolve(path.join(reactNativePath, "rn-get-polyfills")));
29
- }
30
- function loadPolyfillScriptPaths(modulePath, load = require) {
31
- return load(modulePath)();
32
- }
33
- function resolveOptional(moduleId, paths) {
34
- return resolveOptionalWith(() => require.resolve(moduleId, { paths }));
35
- }
36
- function resolveOptionalWith(resolve) {
37
- try {
38
- return resolve();
39
- } catch (error) {
40
- if (error instanceof Error && "code" in error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED")) return;
41
- throw error;
42
- }
43
- }
44
5
  function getGlobalVariables(dev) {
45
6
  return [
46
7
  `var __BUNDLE_START_TIME__ = globalThis.nativePerformanceNow ? nativePerformanceNow() : Date.now();`,
@@ -51,4 +12,4 @@ function getGlobalVariables(dev) {
51
12
  ].filter(isNotNil);
52
13
  }
53
14
  //#endregion
54
- export { getGlobalVariables, resolveAssetRegistryPath, resolveInitializeCorePath, resolvePolyfillScriptPaths };
15
+ export { getGlobalVariables, resolveReactNativeRuntime };
@@ -1,2 +1 @@
1
- import { command } from "./command.js";
2
- export { command };
1
+ export { command } from "./command.js";
@@ -14,6 +14,14 @@ const command = {
14
14
  description: "Path to the CLI configuration file",
15
15
  parse: resolvePath
16
16
  },
17
+ {
18
+ name: "--config-cmd <string>",
19
+ description: "Accepted for React Native Xcode compatibility; ignored."
20
+ },
21
+ {
22
+ name: "--load-config <string>",
23
+ description: "Accepted for React Native Xcode compatibility; ignored."
24
+ },
17
25
  {
18
26
  name: "--entry-file <path>",
19
27
  description: "Path to the root JS file, either absolute or relative to JS root"
@@ -1,2 +1 @@
1
- import { command } from "./command.js";
2
- export { command };
1
+ export { command } from "./command.js";
@@ -1,2 +1 @@
1
- import { command } from "./command.js";
2
- export { command };
1
+ export { command } from "./command.js";
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "1.0.0-beta.1";
2
+ var version = "1.0.0-beta.3";
3
3
  //#endregion
4
4
  export { version };
@@ -0,0 +1,27 @@
1
+ var __create = Object.create;
2
+ __create(null);
3
+ __create(null);
4
+ (function() {
5
+ var r = /* @__PURE__ */ new Uint8Array(128);
6
+ for (var e = 0; e < 64; e++) r[e < 26 ? e + 65 : e < 52 ? e + 71 : e < 62 ? e - 4 : e * 4 - 205] = e;
7
+ return function(e) {
8
+ var t = e.length, o = new Uint8Array((t - (e[t - 1] == "=") - (e[t - 2] == "=")) * 3 / 4 | 0);
9
+ for (var n = 0, _ = 0; n < t;) {
10
+ var a = r[e.charCodeAt(n++)], u = r[e.charCodeAt(n++)];
11
+ var p = r[e.charCodeAt(n++)], f = r[e.charCodeAt(n++)];
12
+ o[_++] = a << 2 | u >> 4;
13
+ o[_++] = u << 4 | p >> 2;
14
+ o[_++] = p << 6 | f;
15
+ }
16
+ return o;
17
+ };
18
+ })();
19
+ (function(r) {
20
+ return typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(r, { get: function r(r, e) {
21
+ return (typeof require !== "undefined" ? require : r)[e];
22
+ } }) : r;
23
+ })(function(r) {
24
+ if (typeof require !== "undefined") return require.apply(this, arguments);
25
+ throw Error("Calling `require` for \"" + r + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
26
+ });
27
+ //#endregion
package/dist/runtime.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import "./rolldown-runtime-BHXq-rbM.js";
1
+ import "./rolldown-runtime-DXE2a-Yu.js";
2
2
  import { createSignatureFunctionForTransform, getFamilyByType, isLikelyComponentType, performReactRefresh, register } from "react-refresh";
3
3
  //#endregion
4
4
  export { setCustomHMRHandler };
package/dist/runtime.js CHANGED
@@ -1,4 +1,4 @@
1
- import "./rolldown-runtime-BHXq-rbM.js";
1
+ import "./rolldown-runtime-DXE2a-Yu.js";
2
2
  //#region src/runtime.ts
3
3
  function setCustomHMRHandler(l) {
4
4
  if (__DEV__ && globalThis.__rollipop_runtime__ != null) {
@@ -7,4 +7,5 @@ export interface BundleStore {
7
7
  sourceMap: string | undefined;
8
8
  sourceMapConsumer: Promise<SourceMapConsumerType> | undefined;
9
9
  }
10
- //#endregion
10
+ //#endregion
11
+ export {};
@@ -57,7 +57,7 @@ async function createDevServer(config, options) {
57
57
  eventBus.subscribe(createReporterEventListener(config.reporter));
58
58
  eventBus.subscribe(createReactNativeEventListener(reportEvent));
59
59
  eventBus.subscribe(createDevServerEventListener(emitter));
60
- const { middleware: devMiddleware, websocketEndpoints } = createDevMiddleware({
60
+ const { middleware: devMiddleware, websocketEndpoints } = options?.inspector ?? createDevMiddleware({
61
61
  serverBaseUrl,
62
62
  logger: {
63
63
  info(...args) {
@@ -18,7 +18,10 @@ function toDevframeEvent(event) {
18
18
  case "bundle_build_failed":
19
19
  case "hmr_failed":
20
20
  case "watch_change": return bundlerEventToDevframeEvent(event);
21
- case "hmr_updates":
21
+ case "hmr_updates": return {
22
+ type: "hmr_updates",
23
+ bundlerId: event.bundlerId
24
+ };
22
25
  case "client_message":
23
26
  case "client_error":
24
27
  case "transform":
@@ -1,5 +1,6 @@
1
1
  import { resetCache } from "../../utils/reset-cache.js";
2
2
  import { getBaseBundleName } from "../../utils/bundle.js";
3
+ import { getHotUpdatePath, parseHotUpdatePath } from "../hot-update-store.js";
3
4
  import { parseUrl } from "../../utils/url.js";
4
5
  import { symbolicate } from "../symbolicate.js";
5
6
  import { toDevframeEvent } from "./events.js";
@@ -20,7 +21,7 @@ var RollipopDevframeController = class {
20
21
  this.definition = defineDevframe({
21
22
  id: "rollipop",
22
23
  name: "Rollipop",
23
- version: "1.0.0-beta.1",
24
+ version: "1.0.0-beta.3",
24
25
  packageName: "rollipop",
25
26
  homepage: "https://github.com/rollipop-dev/rollipop",
26
27
  description: "React Native development dashboard powered by Rollipop.",
@@ -58,6 +59,14 @@ var RollipopDevframeController = class {
58
59
  getBuilds() {
59
60
  return this.context.state.getBuilds();
60
61
  }
62
+ getHmrChunks(bundlerId) {
63
+ return this.context.bundlerPool.hotUpdateStore.list(bundlerId).map((chunk) => ({
64
+ filename: chunk.filename,
65
+ bundleUrl: new URL(getHotUpdatePath(bundlerId, chunk.filename), this.context.serverBaseUrl).href,
66
+ sourceMapUrl: chunk.sourcemapFilename == null ? null : new URL(getHotUpdatePath(bundlerId, chunk.sourcemapFilename), this.context.serverBaseUrl).href,
67
+ updatedAt: chunk.updatedAt
68
+ }));
69
+ }
61
70
  getBuildLogs(bundlerId) {
62
71
  const logs = this.context.state.getBuildLogs(bundlerId);
63
72
  if (logs != null) return logs;
@@ -80,17 +89,26 @@ var RollipopDevframeController = class {
80
89
  }
81
90
  async symbolicateBundlePosition(bundleUrl, line, column) {
82
91
  const { pathname, query } = parseUrl(bundleUrl);
83
- if (pathname == null || query.platform == null || query.dev == null) throw new Error("Bundle URL must include pathname, platform, and dev query parameters");
84
- const bundle = await this.context.bundlerPool.get(getBaseBundleName(pathname), {
85
- platform: String(query.platform),
86
- dev: query.dev === "true",
87
- ...query.minify == null ? {} : { minify: query.minify === "true" }
88
- }).getBundle();
92
+ let bundle;
93
+ if (pathname?.startsWith(`/hot/`)) {
94
+ const hotUpdate = parseHotUpdatePath(pathname);
95
+ if (hotUpdate == null) throw new Error("Invalid HMR chunk URL");
96
+ const stored = this.context.bundlerPool.hotUpdateStore.resolve(hotUpdate.id, hotUpdate.filename);
97
+ if (stored == null) throw new Error(`HMR chunk not found: ${hotUpdate.id}/${hotUpdate.filename}`);
98
+ bundle = stored;
99
+ } else {
100
+ if (pathname == null || query.platform == null || query.dev == null) throw new Error("Bundle URL must include pathname, platform, and dev query parameters");
101
+ bundle = await this.context.bundlerPool.get(getBaseBundleName(pathname), {
102
+ platform: String(query.platform),
103
+ dev: query.dev === "true",
104
+ ...query.minify == null ? {} : { minify: query.minify === "true" }
105
+ }).getBundle();
106
+ }
89
107
  return symbolicate(bundle, [{
90
108
  file: bundleUrl,
91
109
  lineNumber: line + 1,
92
110
  column
93
- }]);
111
+ }], { fallbackToNextMapping: true });
94
112
  }
95
113
  async triggerFullBuild(bundlerId) {
96
114
  const bundler = this.context.bundlerPool.getInstanceById(bundlerId);
@@ -124,6 +142,11 @@ function registerDashboardRpcFunctions(rpc, controller) {
124
142
  type: "query",
125
143
  handler: () => controller.getBuilds()
126
144
  }));
145
+ rpc.register(defineRpcFunction({
146
+ name: "get-hmr-chunks",
147
+ type: "query",
148
+ handler: (bundlerId) => controller.getHmrChunks(bundlerId)
149
+ }));
127
150
  rpc.register(defineRpcFunction({
128
151
  name: "get-build-logs",
129
152
  type: "query",
@@ -16,7 +16,7 @@ async function setupDevframe(context, server, inspectorDeviceServer) {
16
16
  const controller = new RollipopDevframeController(context, createAgentToolContext(context));
17
17
  const devtools = initHub({
18
18
  name: DEVFRAME_NAME,
19
- version: "1.0.0-beta.1",
19
+ version: "1.0.0-beta.3",
20
20
  base: ROLLIPOP_DEVFRAME_BASE,
21
21
  cwd: context.config.root,
22
22
  ui: createUi({
@@ -39,6 +39,9 @@ async function setupDevframe(context, server, inspectorDeviceServer) {
39
39
  mcp: mcpEnabled ? { path: ROLLIPOP_DEVFRAME_MCP_PATH } : false,
40
40
  origin: context.serverBaseUrl,
41
41
  configure: async (devtoolsContext) => {
42
+ (await devtoolsContext.rpc.sharedState.get("devframe:user-settings")).mutate((state) => {
43
+ state.autoCollapseEdgeToolbar ??= false;
44
+ });
42
45
  await controller.definition.setup(devtoolsContext);
43
46
  await invokeDevToolsSetup(devtoolsContext, server, context.config.plugins ?? []);
44
47
  }
@@ -8,11 +8,18 @@ export interface HotUpdatePatch {
8
8
  }
9
9
  export declare class HotUpdateStore {
10
10
  private readonly hotPath;
11
+ private readonly patches;
11
12
  constructor(projectRoot: string);
12
13
  clear(): void;
13
14
  write(id: string, patch: HotUpdatePatch): void;
15
+ list(id: string): {
16
+ filename: string;
17
+ sourcemapFilename: string | null;
18
+ updatedAt: number;
19
+ }[];
14
20
  resolve(id: string, filename: string): BundleStore | undefined;
15
21
  readAsset(id: string, filename: string): Buffer | undefined;
22
+ private getSourcemapFilename;
16
23
  private getDirectoryPath;
17
24
  private getFilePath;
18
25
  }
@@ -27,10 +27,12 @@ function parseHotUpdatePath(pathname) {
27
27
  }
28
28
  var HotUpdateStore = class {
29
29
  hotPath;
30
+ patches = /* @__PURE__ */ new Map();
30
31
  constructor(projectRoot) {
31
32
  this.hotPath = path.join(FileStorage.getPath(projectRoot), "hot");
32
33
  }
33
34
  clear() {
35
+ this.patches.clear();
34
36
  try {
35
37
  fs.rmSync(this.hotPath, {
36
38
  recursive: true,
@@ -47,14 +49,29 @@ var HotUpdateStore = class {
47
49
  fs.mkdirSync(directoryPath, { recursive: true });
48
50
  if (patch.sourcemap != null && patch.sourcemapFilename != null) fs.writeFileSync(this.getFilePath(id, patch.sourcemapFilename), patch.sourcemap, "utf-8");
49
51
  fs.writeFileSync(this.getFilePath(id, patch.filename), patch.code, "utf-8");
52
+ const patches = this.patches.get(id) ?? /* @__PURE__ */ new Map();
53
+ patches.set(patch.filename, patch.sourcemapFilename ?? null);
54
+ this.patches.set(id, patches);
55
+ }
56
+ list(id) {
57
+ assertPathSegment(id, "id");
58
+ return Array.from(this.patches.get(id)?.keys() ?? []).flatMap((filename) => {
59
+ const stats = fs.statSync(this.getFilePath(id, filename), { throwIfNoEntry: false });
60
+ if (!stats?.isFile()) return [];
61
+ return [{
62
+ filename,
63
+ sourcemapFilename: this.getSourcemapFilename(id, filename),
64
+ updatedAt: stats.mtimeMs
65
+ }];
66
+ }).sort((a, b) => b.updatedAt - a.updatedAt);
50
67
  }
51
68
  resolve(id, filename) {
52
69
  assertPathSegment(id, "id");
53
70
  assertPathSegment(filename, "filename");
54
71
  const bundleFilePath = this.getFilePath(id, filename);
55
72
  if (!isFile(bundleFilePath)) return;
56
- const sourcemapFilePath = this.getFilePath(id, `${filename}.map`);
57
- return new HotUpdateBundleStore(bundleFilePath, isFile(sourcemapFilePath) ? sourcemapFilePath : void 0);
73
+ const sourcemapFilename = this.getSourcemapFilename(id, filename);
74
+ return new HotUpdateBundleStore(bundleFilePath, sourcemapFilename == null ? void 0 : this.getFilePath(id, sourcemapFilename));
58
75
  }
59
76
  readAsset(id, filename) {
60
77
  assertPathSegment(id, "id");
@@ -62,6 +79,11 @@ var HotUpdateStore = class {
62
79
  const filePath = this.getFilePath(id, filename);
63
80
  return isFile(filePath) ? fs.readFileSync(filePath) : void 0;
64
81
  }
82
+ getSourcemapFilename(id, filename) {
83
+ const storedFilename = this.patches.get(id)?.get(filename);
84
+ const sourcemapFilename = storedFilename === void 0 ? `${filename}.map` : storedFilename;
85
+ return sourcemapFilename != null && isFile(this.getFilePath(id, sourcemapFilename)) ? sourcemapFilename : null;
86
+ }
65
87
  getDirectoryPath(id) {
66
88
  return path.join(this.hotPath, id);
67
89
  }
@@ -1,4 +1,5 @@
1
1
  import { parseUrl } from "../utils/url.js";
2
+ import { SourceMapConsumer } from "source-map";
2
3
  import { codeFrameColumns } from "@babel/code-frame";
3
4
  //#region src/server/symbolicate.ts
4
5
  /**
@@ -25,16 +26,16 @@ const INTERNAL_CALLSITES_REGEX = new RegExp([
25
26
  "/node_modules/scheduler/.+\\.js$",
26
27
  "^\\[native code\\]$"
27
28
  ].map((pathPattern) => pathPattern.replaceAll("/", "[/\\\\]")).join("|"));
28
- async function symbolicate(bundleStore, stack) {
29
- return symbolicateWithBundleResolver(stack, (frame) => frame.file?.startsWith("http") ? bundleStore : void 0);
29
+ async function symbolicate(bundleStore, stack, options) {
30
+ return symbolicateWithBundleResolver(stack, (frame) => frame.file?.startsWith("http") ? bundleStore : void 0, options);
30
31
  }
31
- async function symbolicateWithBundleResolver(stack, resolveBundleStore) {
32
+ async function symbolicateWithBundleResolver(stack, resolveBundleStore, options) {
32
33
  const symbolicatedStack = await Promise.all(stack.map(async (frame) => {
33
34
  const bundleStore = frame.file?.startsWith("http") ? await resolveBundleStore(frame) : void 0;
34
35
  const sourceMapConsumer = await bundleStore?.sourceMapConsumer;
35
36
  return {
36
37
  bundleStore,
37
- frame: collapseFrame(sourceMapConsumer ? originalPositionFor(sourceMapConsumer, frame) : frame),
38
+ frame: collapseFrame(sourceMapConsumer ? originalPositionFor(sourceMapConsumer, frame, options) : frame),
38
39
  sourceMapConsumer
39
40
  };
40
41
  }));
@@ -43,12 +44,17 @@ async function symbolicateWithBundleResolver(stack, resolveBundleStore) {
43
44
  codeFrame: getCodeFrame(symbolicatedStack)
44
45
  };
45
46
  }
46
- function originalPositionFor(sourceMapConsumer, frame) {
47
+ function originalPositionFor(sourceMapConsumer, frame, options) {
47
48
  if (frame.column == null || frame.lineNumber == null) return frame;
48
- const originalPosition = sourceMapConsumer.originalPositionFor({
49
+ let originalPosition = sourceMapConsumer.originalPositionFor({
49
50
  column: frame.column,
50
51
  line: frame.lineNumber
51
52
  });
53
+ if (originalPosition.source == null && options?.fallbackToNextMapping) originalPosition = sourceMapConsumer.originalPositionFor({
54
+ column: frame.column,
55
+ line: frame.lineNumber,
56
+ bias: SourceMapConsumer.LEAST_UPPER_BOUND
57
+ });
52
58
  return Object.entries(originalPosition).reduce((frame, [key, value]) => {
53
59
  const targetKey = convertFrameKey(key);
54
60
  return {
@@ -22,6 +22,11 @@ export interface ServerOptions {
22
22
  key?: string;
23
23
  cert?: string;
24
24
  buildOptions?: Pick<BuildOptions, 'cache'>;
25
+ /** Override the inspector middleware and WebSocket endpoints for a host's debugging protocol. */
26
+ inspector?: {
27
+ middleware: fastifyMiddie.Handler;
28
+ websocketEndpoints: Record<string, ws.Server>;
29
+ };
25
30
  }
26
31
  export interface DevServerContext {
27
32
  /**
@@ -28,7 +28,7 @@ var FileStorage = class FileStorage {
28
28
  this.dataFilePath = path.join(FileStorage.getPath(basePath, { prepare: true }), DATA_FILENAME);
29
29
  if (fs.existsSync(this.dataFilePath)) {
30
30
  const loadedData = JSON.parse(fs.readFileSync(this.dataFilePath, "utf-8"));
31
- if ("version" in loadedData && loadedData.version === "1.0.0-beta.1") this.data = loadedData;
31
+ if ("version" in loadedData && loadedData.version === "1.0.0-beta.3") this.data = loadedData;
32
32
  else {
33
33
  this.data = createDefaultData();
34
34
  this.flush();
@@ -1,3 +1,4 @@
1
+ import { resolveWorkletsConfig } from "./worklets.js";
1
2
  import { RollipopReactNativeTransformer } from "@rollipop/rolldown/experimental";
2
3
  //#region src/utils/transform.ts
3
4
  const transformers = /* @__PURE__ */ new WeakMap();
@@ -8,7 +9,7 @@ function transformWithRollipop(id, code, config) {
8
9
  envName: config.mode,
9
10
  runtimeTarget: config.runtimeTarget,
10
11
  flow: config.transform.flow,
11
- worklets: config.experimental.worklets,
12
+ worklets: resolveWorkletsConfig(config.experimental.worklets, config),
12
13
  swc: {
13
14
  externalHelpers: true,
14
15
  ...config.transform.swc?.native
@@ -0,0 +1,7 @@
1
+ import { RollipopReactNativeWorkletsConfig as WorkletsConfig } from "../config/types.js";
2
+ import "../config/index.js";
3
+ import { ResolvedConfig } from "../config/defaults.js";
4
+ import { RollipopReactNativeWorkletsConfig } from "@rollipop/rolldown/experimental";
5
+ //#region src/utils/worklets.d.ts
6
+ export declare function resolveWorkletsConfig(worklets: WorkletsConfig | undefined, { root, mode }: Pick<ResolvedConfig, 'root' | 'mode'>): RollipopReactNativeWorkletsConfig | undefined;
7
+ //#endregion
@@ -0,0 +1,32 @@
1
+ import { resolvePackageJson } from "./node-resolve.js";
2
+ import { satisfies } from "semver";
3
+ //#region src/utils/worklets.ts
4
+ function resolveWorkletsConfig(worklets, { root, mode }) {
5
+ if (worklets == null) return;
6
+ const { pluginVersion, reanimatedVersion, ...options } = worklets;
7
+ const defaults = {
8
+ ...options,
9
+ isRelease: options.isRelease ?? mode === "production"
10
+ };
11
+ if (pluginVersion != null) return {
12
+ ...defaults,
13
+ pluginVersion
14
+ };
15
+ if (reanimatedVersion != null) return {
16
+ ...defaults,
17
+ reanimatedVersion
18
+ };
19
+ const installedReanimatedVersion = resolvePackageJson(root, "react-native-reanimated")?.version;
20
+ if (installedReanimatedVersion != null && satisfies(installedReanimatedVersion, "3.x", { includePrerelease: true })) return {
21
+ ...defaults,
22
+ reanimatedVersion: installedReanimatedVersion
23
+ };
24
+ const installedWorkletsVersion = resolvePackageJson(root, "react-native-worklets")?.version;
25
+ if (installedWorkletsVersion != null) return {
26
+ ...defaults,
27
+ pluginVersion: installedWorkletsVersion
28
+ };
29
+ throw new Error("Could not resolve a worklet runtime. Install react-native-reanimated 3.x or react-native-worklets, or set reanimatedVersion or pluginVersion in the worklets configuration.");
30
+ }
31
+ //#endregion
32
+ export { resolveWorkletsConfig };