rollipop 1.0.0-alpha.31 → 1.0.0-alpha.32
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/constants.js +1 -1
- package/dist/core/bundler.js +13 -0
- package/dist/core/env.js +12 -8
- package/dist/node/commands/bundle/command.js +2 -2
- package/dist/package.js +1 -1
- package/dist/server/bundler-pool.js +1 -1
- package/dist/server/create-dev-server.js +1 -1
- package/dist/server/devframe/index.js +1 -1
- package/dist/server/devframe/setup.js +11 -2
- package/dist/server/middlewares/serve-assets.js +33 -5
- package/dist/storage/file-storage.js +1 -1
- package/package.json +2 -2
package/dist/constants.js
CHANGED
|
@@ -20,7 +20,7 @@ var constants_exports = /* @__PURE__ */ __exportAll({
|
|
|
20
20
|
ROLLIPOP_VIRTUAL_ENTRY_ID: () => ROLLIPOP_VIRTUAL_ENTRY_ID,
|
|
21
21
|
ROLLIPOP_VIRTUAL_PREFIX: () => ROLLIPOP_VIRTUAL_PREFIX
|
|
22
22
|
});
|
|
23
|
-
const ROLLIPOP_VERSION = "1.0.0-alpha.
|
|
23
|
+
const ROLLIPOP_VERSION = "1.0.0-alpha.32";
|
|
24
24
|
const ROLLIPOP_VIRTUAL_PREFIX = "\0rollipop/";
|
|
25
25
|
const ROLLIPOP_VIRTUAL_BOOTSTRAP_ID = `${ROLLIPOP_VIRTUAL_PREFIX}bootstrap`;
|
|
26
26
|
const ROLLIPOP_VIRTUAL_ENTRY_ID = `${ROLLIPOP_VIRTUAL_PREFIX}entry`;
|
package/dist/core/bundler.js
CHANGED
|
@@ -3,6 +3,7 @@ import { EventBus } from "../events/event-bus.js";
|
|
|
3
3
|
import { FileStorage } from "../storage/file-storage.js";
|
|
4
4
|
import { resolveBuildOptions } from "../utils/build-options.js";
|
|
5
5
|
import { createId } from "../utils/id.js";
|
|
6
|
+
import { replaceSourceMappingUrl } from "../utils/source-map.js";
|
|
6
7
|
import { resolveRolldownOptions } from "./rolldown.js";
|
|
7
8
|
import fs from "node:fs";
|
|
8
9
|
import path from "node:path";
|
|
@@ -81,6 +82,18 @@ var Bundler = class Bundler {
|
|
|
81
82
|
const sourcemapFile = path.join(outputDir, chunk.sourcemapFileName);
|
|
82
83
|
if (!fs.existsSync(sourcemapDir)) fs.mkdirSync(sourcemapDir, { recursive: true });
|
|
83
84
|
fs.renameSync(sourcemapFile, resolvedBuildOptions.sourcemapOutfile);
|
|
85
|
+
const sourcemapFileName = path.relative(outputDir, resolvedBuildOptions.sourcemapOutfile).split(path.sep).join("/");
|
|
86
|
+
let code = chunk.code;
|
|
87
|
+
if (output.sourcemap !== "hidden") {
|
|
88
|
+
const sourceMapUrl = sourcemapFileName.split("/").map(encodeURIComponent).join("/");
|
|
89
|
+
code = replaceSourceMappingUrl(code, output.sourcemapBaseUrl ? new URL(sourceMapUrl, output.sourcemapBaseUrl).href : sourceMapUrl);
|
|
90
|
+
fs.writeFileSync(resolvedBuildOptions.outfile, code);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
...chunk,
|
|
94
|
+
code,
|
|
95
|
+
sourcemapFileName
|
|
96
|
+
};
|
|
84
97
|
}
|
|
85
98
|
return chunk;
|
|
86
99
|
}
|
package/dist/core/env.js
CHANGED
|
@@ -10,6 +10,7 @@ function loadEnv(options) {
|
|
|
10
10
|
invariant(envPrefix.length > 0, "`envPrefix` is required");
|
|
11
11
|
invariant(envFile.length > 0, "`envFile` is required");
|
|
12
12
|
const env = {};
|
|
13
|
+
const parsed = {};
|
|
13
14
|
const envFilesToLoad = [
|
|
14
15
|
envFile,
|
|
15
16
|
`${envFile}.local`,
|
|
@@ -20,15 +21,18 @@ function loadEnv(options) {
|
|
|
20
21
|
const envPath = path.resolve(envDir, file);
|
|
21
22
|
if (!fs.existsSync(envPath)) continue;
|
|
22
23
|
logger.trace(`Loading environment variables from ${envPath}`);
|
|
23
|
-
|
|
24
|
-
const expanded = dotenvExpand.expand({
|
|
25
|
-
parsed,
|
|
26
|
-
processEnv: {}
|
|
27
|
-
});
|
|
28
|
-
if (expanded.parsed) Object.entries(expanded.parsed).forEach(([key, value]) => {
|
|
29
|
-
if (key.startsWith(envPrefix)) env[key] = key in process.env ? process.env[key] : value;
|
|
30
|
-
});
|
|
24
|
+
Object.assign(parsed, dotenv.parse(fs.readFileSync(envPath, "utf-8")));
|
|
31
25
|
}
|
|
26
|
+
const processEnv = {};
|
|
27
|
+
for (const [key, value] of Object.entries(process.env)) if (value !== void 0) {
|
|
28
|
+
processEnv[key] = value;
|
|
29
|
+
if (key in parsed) parsed[key] = value;
|
|
30
|
+
}
|
|
31
|
+
const expanded = dotenvExpand.expand({
|
|
32
|
+
parsed,
|
|
33
|
+
processEnv
|
|
34
|
+
});
|
|
35
|
+
for (const [key, value] of Object.entries(expanded.parsed ?? {})) if (key.startsWith(envPrefix)) env[key] = process.env[key] ?? value;
|
|
32
36
|
logger.trace("Loaded environment variables:", env);
|
|
33
37
|
return env;
|
|
34
38
|
}
|
|
@@ -25,12 +25,12 @@ const command = {
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
name: "--dev [boolean]",
|
|
28
|
-
description: "
|
|
28
|
+
description: "Build in development mode. Defaults to whether config.mode is development",
|
|
29
29
|
parse: parseBoolean
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
name: "--minify [boolean]",
|
|
33
|
-
description: "
|
|
33
|
+
description: "Override output.minify from the configuration. Defaults to false when not configured, regardless of --dev.",
|
|
34
34
|
parse: parseBoolean
|
|
35
35
|
},
|
|
36
36
|
{
|
package/dist/package.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveBuildOptions } from "../utils/build-options.js";
|
|
2
|
+
import { replaceSourceMappingUrl } from "../utils/source-map.js";
|
|
2
3
|
import { bindReporter } from "../utils/config.js";
|
|
3
4
|
import { getBaseUrl } from "../utils/server.js";
|
|
4
|
-
import { replaceSourceMappingUrl } from "../utils/source-map.js";
|
|
5
5
|
import { Bundler } from "../core/bundler.js";
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
7
|
import { getBaseBundleName } from "../utils/bundle.js";
|
|
@@ -121,7 +121,7 @@ async function createDevServer(config, options) {
|
|
|
121
121
|
middlewares: { use: fastify.use.bind(fastify) }
|
|
122
122
|
};
|
|
123
123
|
const { invokePostConfigureServer } = await invokeConfigureServer(devServer, config.plugins ?? []);
|
|
124
|
-
const devframeMiddleware = await setupDevframe(context, devServer);
|
|
124
|
+
const devframeMiddleware = await setupDevframe(context, devServer, websocketEndpoints["/inspector/device"]);
|
|
125
125
|
fastify.use(requestLogger).use(devframeMiddleware).use(communityMiddleware).use(devMiddleware).register(plugin, { context }).register(plugin$3, { hotUpdateStore: bundlerPool.hotUpdateStore }).register(plugin$4, { context }).register(plugin$2, { context }).register(plugin$1, { context });
|
|
126
126
|
fastify.setErrorHandler(errorHandler);
|
|
127
127
|
const upgradeHandler = getWebSocketUpgradeHandler({
|
|
@@ -24,7 +24,7 @@ var RollipopDevframeController = class {
|
|
|
24
24
|
this.definition = defineDevframe({
|
|
25
25
|
id: "rollipop",
|
|
26
26
|
name: "Rollipop",
|
|
27
|
-
version: "1.0.0-alpha.
|
|
27
|
+
version: "1.0.0-alpha.32",
|
|
28
28
|
packageName: "rollipop",
|
|
29
29
|
homepage: "https://github.com/rollipop-dev/rollipop",
|
|
30
30
|
description: "React Native development dashboard powered by Rollipop.",
|
|
@@ -11,12 +11,12 @@ const DEVFRAME_NAME = "Rollipop";
|
|
|
11
11
|
const ROLLIPOP_DEVFRAME_BASE = "/__rollipop/";
|
|
12
12
|
const ROLLIPOP_DEVFRAME_SSE_ROUTE = "__sse";
|
|
13
13
|
const ROLLIPOP_DEVFRAME_MCP_PATH = "__mcp";
|
|
14
|
-
async function setupDevframe(context, server) {
|
|
14
|
+
async function setupDevframe(context, server, inspectorDeviceServer) {
|
|
15
15
|
const mcpEnabled = isAgenticInstalled();
|
|
16
16
|
const controller = new RollipopDevframeController(context, createAgentToolContext(context));
|
|
17
17
|
const devtools = initHub({
|
|
18
18
|
name: DEVFRAME_NAME,
|
|
19
|
-
version: "1.0.0-alpha.
|
|
19
|
+
version: "1.0.0-alpha.32",
|
|
20
20
|
base: ROLLIPOP_DEVFRAME_BASE,
|
|
21
21
|
cwd: context.config.root,
|
|
22
22
|
ui: createUi({
|
|
@@ -44,6 +44,13 @@ async function setupDevframe(context, server) {
|
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
await devtools.ready;
|
|
47
|
+
const refreshDevices = () => {
|
|
48
|
+
controller.refresh();
|
|
49
|
+
};
|
|
50
|
+
const onDeviceConnection = (socket) => {
|
|
51
|
+
socket.once("close", refreshDevices);
|
|
52
|
+
};
|
|
53
|
+
inspectorDeviceServer?.on("connection", onDeviceConnection);
|
|
47
54
|
server.instance.addHook("onListen", () => {
|
|
48
55
|
if (mcpEnabled) {
|
|
49
56
|
const mcpUrl = getServerDisplayUrl(server.instance.listeningOrigin, "/__rollipop/__mcp");
|
|
@@ -52,6 +59,8 @@ async function setupDevframe(context, server) {
|
|
|
52
59
|
controller.refresh();
|
|
53
60
|
});
|
|
54
61
|
server.instance.addHook("preClose", async () => {
|
|
62
|
+
inspectorDeviceServer?.off("connection", onDeviceConnection);
|
|
63
|
+
for (const socket of inspectorDeviceServer?.clients ?? []) socket.off("close", refreshDevices);
|
|
55
64
|
controller.dispose();
|
|
56
65
|
await devtools.close();
|
|
57
66
|
});
|
|
@@ -16,20 +16,34 @@ const queryParamSchema = asConst({
|
|
|
16
16
|
});
|
|
17
17
|
const plugin = fp((fastify, options) => {
|
|
18
18
|
const { context } = options;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const projectRoot = path.resolve(context.config.root);
|
|
20
|
+
const workspaceRoot = findWorkspaceRoot(projectRoot);
|
|
21
|
+
const assetExtensions = new Set(context.config.resolve.assetExtensions);
|
|
22
22
|
fastify.get(`/${DEV_SERVER_ASSET_PATH}/*`, {
|
|
23
23
|
schema: { querystring: queryParamSchema },
|
|
24
24
|
async handler(request, reply) {
|
|
25
25
|
const { params, query } = request;
|
|
26
|
-
const assetPath =
|
|
26
|
+
const assetPath = path.resolve(projectRoot, params["*"]);
|
|
27
|
+
if (!assetExtensions.has(path.extname(assetPath).slice(1))) {
|
|
28
|
+
await reply.status(403).send();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
27
31
|
try {
|
|
32
|
+
const realWorkspaceRoot = await fs.promises.realpath(workspaceRoot);
|
|
33
|
+
if (!isWithin(realWorkspaceRoot, await fs.promises.realpath(path.dirname(assetPath)))) {
|
|
34
|
+
await reply.status(403).send();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
28
37
|
const resolvedAssetPath = resolveAssetPath(assetPath, {
|
|
29
38
|
platform: query.platform,
|
|
30
39
|
preferNativePlatform: context.config.resolve.preferNativePlatform
|
|
31
40
|
});
|
|
32
|
-
const
|
|
41
|
+
const realAssetPath = await fs.promises.realpath(resolvedAssetPath);
|
|
42
|
+
if (!isWithin(realWorkspaceRoot, realAssetPath)) {
|
|
43
|
+
await reply.status(403).send();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const [assetData, { size }] = await Promise.all([fs.promises.readFile(realAssetPath), fs.promises.stat(realAssetPath)]);
|
|
33
47
|
await reply.header("Content-Type", mime.getType(resolvedAssetPath) ?? "").header("Content-Length", size).send(assetData);
|
|
34
48
|
} catch (error) {
|
|
35
49
|
fastify.log.error(error, "Failed to serve asset");
|
|
@@ -38,5 +52,19 @@ const plugin = fp((fastify, options) => {
|
|
|
38
52
|
}
|
|
39
53
|
});
|
|
40
54
|
}, { name: "serve-assets" });
|
|
55
|
+
function isWithin(root, file) {
|
|
56
|
+
const relative = path.relative(root, file);
|
|
57
|
+
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
58
|
+
}
|
|
59
|
+
function findWorkspaceRoot(projectRoot) {
|
|
60
|
+
let directory = projectRoot;
|
|
61
|
+
while (true) {
|
|
62
|
+
const packageJson = path.join(directory, "package.json");
|
|
63
|
+
if (fs.existsSync(path.join(directory, "pnpm-workspace.yaml")) || fs.existsSync(packageJson) && JSON.parse(fs.readFileSync(packageJson, "utf-8")).workspaces) return directory;
|
|
64
|
+
const parent = path.dirname(directory);
|
|
65
|
+
if (parent === directory) return projectRoot;
|
|
66
|
+
directory = parent;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
41
69
|
//#endregion
|
|
42
70
|
export { plugin as serveAssets };
|
|
@@ -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-alpha.
|
|
31
|
+
if ("version" in loadedData && loadedData.version === "1.0.0-alpha.32") this.data = loadedData;
|
|
32
32
|
else {
|
|
33
33
|
this.data = createDefaultData();
|
|
34
34
|
this.flush();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rollipop",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.32",
|
|
4
4
|
"homepage": "https://github.com/rollipop-dev/rollipop#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/rollipop-dev/rollipop/issues"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@react-native-community/cli-server-api": "20.2.0",
|
|
68
68
|
"@react-native-community/cli-types": "20.2.0",
|
|
69
69
|
"@react-native/dev-middleware": "0.87.1",
|
|
70
|
-
"@rollipop/dashboard": "1.0.0-alpha.
|
|
70
|
+
"@rollipop/dashboard": "1.0.0-alpha.32",
|
|
71
71
|
"@rollipop/rolldown": "1.0.32",
|
|
72
72
|
"@swc/core": "1.15.43",
|
|
73
73
|
"@swc/helpers": "0.5.23",
|