@expo/cli 55.0.0-canary-20260105-6b962e6 → 55.0.0-canary-20260119-70f7c28
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/build/bin/cli +1 -1
- package/build/src/export/embed/exportEmbedAsync.js +1 -2
- package/build/src/export/embed/exportEmbedAsync.js.map +1 -1
- package/build/src/export/exportStaticAsync.js +117 -7
- package/build/src/export/exportStaticAsync.js.map +1 -1
- package/build/src/export/saveAssets.js +6 -4
- package/build/src/export/saveAssets.js.map +1 -1
- package/build/src/start/interface/interactiveActions.js +0 -1
- package/build/src/start/interface/interactiveActions.js.map +1 -1
- package/build/src/start/server/Bonjour.js +100 -0
- package/build/src/start/server/Bonjour.js.map +1 -0
- package/build/src/start/server/BundlerDevServer.js +22 -4
- package/build/src/start/server/BundlerDevServer.js.map +1 -1
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +2 -2
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -1
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js +86 -0
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js.map +1 -0
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js +67 -0
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js.map +1 -0
- package/build/src/start/server/metro/DevToolsPluginWebsocketEndpoint.js +10 -2
- package/build/src/start/server/metro/DevToolsPluginWebsocketEndpoint.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +103 -31
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/createServerRouteMiddleware.js +25 -1
- package/build/src/start/server/metro/createServerRouteMiddleware.js.map +1 -1
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js +22 -8
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js.map +1 -1
- package/build/src/start/server/metro/dev-server/compression.js +45 -0
- package/build/src/start/server/metro/dev-server/compression.js.map +1 -0
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js +2 -2
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js.map +1 -1
- package/build/src/start/server/metro/instantiateMetro.js +19 -7
- package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
- package/build/src/start/server/metro/resolveLoader.js +2 -1
- package/build/src/start/server/metro/resolveLoader.js.map +1 -1
- package/build/src/start/server/middleware/metroOptions.js +3 -2
- package/build/src/start/server/middleware/metroOptions.js.map +1 -1
- package/build/src/start/startAsync.js +6 -1
- package/build/src/start/startAsync.js.map +1 -1
- package/build/src/utils/env.js +15 -1
- package/build/src/utils/env.js.map +1 -1
- package/build/src/utils/git.js +1 -1
- package/build/src/utils/git.js.map +1 -1
- package/build/src/utils/net.js +43 -0
- package/build/src/utils/net.js.map +1 -0
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +22 -21
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js +0 -75
- package/build/src/start/server/middleware/DataLoaderModuleMiddleware.js.map +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "addMcpCapabilities", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return addMcpCapabilities;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _DevToolsPluginschema = require("./DevToolsPlugin.schema");
|
|
12
|
+
const _DevToolsPluginCliExtensionExecutor = require("./DevToolsPluginCliExtensionExecutor");
|
|
13
|
+
const _createMCPDevToolsExtensionSchema = require("./createMCPDevToolsExtensionSchema");
|
|
14
|
+
const _log = require("../../log");
|
|
15
|
+
const debug = require('debug')('expo:start:server:devtools:mcp');
|
|
16
|
+
async function addMcpCapabilities(mcpServer, devServerManager) {
|
|
17
|
+
const plugins = await devServerManager.devtoolsPluginManager.queryPluginsAsync();
|
|
18
|
+
for (const plugin of plugins){
|
|
19
|
+
if (plugin.cliExtensions) {
|
|
20
|
+
const commands = (plugin.cliExtensions.commands ?? []).filter((p)=>{
|
|
21
|
+
var _p_environments;
|
|
22
|
+
return (_p_environments = p.environments) == null ? void 0 : _p_environments.includes('mcp');
|
|
23
|
+
});
|
|
24
|
+
if (commands.length === 0) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const schema = (0, _createMCPDevToolsExtensionSchema.createMCPDevToolsExtensionSchema)(plugin);
|
|
28
|
+
debug(`Installing MCP CLI extension for plugin: ${plugin.packageName} - found ${commands.length} commands`);
|
|
29
|
+
mcpServer.registerTool(plugin.packageName, {
|
|
30
|
+
title: plugin.packageName,
|
|
31
|
+
description: plugin.description,
|
|
32
|
+
inputSchema: {
|
|
33
|
+
parameters: schema
|
|
34
|
+
}
|
|
35
|
+
}, async ({ parameters })=>{
|
|
36
|
+
try {
|
|
37
|
+
const { command, ...args } = parameters;
|
|
38
|
+
const metroServerOrigin = devServerManager.getDefaultDevServer().getJsInspectorBaseUrl();
|
|
39
|
+
const results = await new _DevToolsPluginCliExtensionExecutor.DevToolsPluginCliExtensionExecutor(plugin, devServerManager.projectRoot).execute({
|
|
40
|
+
command,
|
|
41
|
+
args,
|
|
42
|
+
metroServerOrigin
|
|
43
|
+
});
|
|
44
|
+
const parsedResults = _DevToolsPluginschema.DevToolsPluginOutputSchema.safeParse(results);
|
|
45
|
+
if (parsedResults.success === false) {
|
|
46
|
+
throw new Error(`Invalid output from CLI command: ${parsedResults.error.issues.map((issue)=>issue.message).join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
content: parsedResults.data.map((line)=>{
|
|
50
|
+
const { type } = line;
|
|
51
|
+
if (type === 'text') {
|
|
52
|
+
return {
|
|
53
|
+
type,
|
|
54
|
+
text: line.text,
|
|
55
|
+
level: line.level,
|
|
56
|
+
url: line.url
|
|
57
|
+
};
|
|
58
|
+
} else if (line.type === 'image' || line.type === 'audio') {
|
|
59
|
+
// We could present this as a resource_link, but it seems not to be well supported in MCP clients,
|
|
60
|
+
// so we'll return a text with the link instead.
|
|
61
|
+
return {
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: `${type} resource: ${line.url}${line.text ? ' (' + line.text + ')' : ''}`
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}).filter((line)=>line !== null)
|
|
68
|
+
};
|
|
69
|
+
} catch (e) {
|
|
70
|
+
_log.Log.error('Error executing MCP CLI command:', e);
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: `Error executing command: ${e.toString()}`
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
isError: true
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=MCPDevToolsPluginCLIExtensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/MCPDevToolsPluginCLIExtensions.ts"],"sourcesContent":["import { DevServerManager } from './DevServerManager';\nimport { DevToolsPluginOutputSchema } from './DevToolsPlugin.schema';\nimport { DevToolsPluginCliExtensionExecutor } from './DevToolsPluginCliExtensionExecutor';\nimport { McpServer } from './MCP';\nimport { createMCPDevToolsExtensionSchema } from './createMCPDevToolsExtensionSchema';\nimport { Log } from '../../log';\n\nconst debug = require('debug')('expo:start:server:devtools:mcp');\n\nexport async function addMcpCapabilities(mcpServer: McpServer, devServerManager: DevServerManager) {\n const plugins = await devServerManager.devtoolsPluginManager.queryPluginsAsync();\n\n for (const plugin of plugins) {\n if (plugin.cliExtensions) {\n const commands = (plugin.cliExtensions.commands ?? []).filter((p) =>\n p.environments?.includes('mcp')\n );\n if (commands.length === 0) {\n continue;\n }\n\n const schema = createMCPDevToolsExtensionSchema(plugin);\n\n debug(\n `Installing MCP CLI extension for plugin: ${plugin.packageName} - found ${commands.length} commands`\n );\n\n mcpServer.registerTool(\n plugin.packageName,\n {\n title: plugin.packageName,\n description: plugin.description,\n inputSchema: { parameters: schema },\n },\n async ({ parameters }) => {\n try {\n const { command, ...args } = parameters;\n\n const metroServerOrigin = devServerManager\n .getDefaultDevServer()\n .getJsInspectorBaseUrl();\n\n const results = await new DevToolsPluginCliExtensionExecutor(\n plugin,\n devServerManager.projectRoot\n ).execute({ command, args, metroServerOrigin });\n\n const parsedResults = DevToolsPluginOutputSchema.safeParse(results);\n if (parsedResults.success === false) {\n throw new Error(\n `Invalid output from CLI command: ${parsedResults.error.issues\n .map((issue) => issue.message)\n .join(', ')}`\n );\n }\n return {\n content: parsedResults.data\n .map((line) => {\n const { type } = line;\n if (type === 'text') {\n return { type, text: line.text, level: line.level, url: line.url };\n } else if (line.type === 'image' || line.type === 'audio') {\n // We could present this as a resource_link, but it seems not to be well supported in MCP clients,\n // so we'll return a text with the link instead.\n return {\n type: 'text',\n text: `${type} resource: ${line.url}${line.text ? ' (' + line.text + ')' : ''}`,\n } as const;\n }\n return null;\n })\n .filter((line): line is Exclude<typeof line, null> => line !== null),\n };\n } catch (e: any) {\n Log.error('Error executing MCP CLI command:', e);\n return {\n content: [{ type: 'text', text: `Error executing command: ${e.toString()}` }],\n isError: true,\n };\n }\n }\n );\n }\n }\n}\n"],"names":["addMcpCapabilities","debug","require","mcpServer","devServerManager","plugins","devtoolsPluginManager","queryPluginsAsync","plugin","cliExtensions","commands","filter","p","environments","includes","length","schema","createMCPDevToolsExtensionSchema","packageName","registerTool","title","description","inputSchema","parameters","command","args","metroServerOrigin","getDefaultDevServer","getJsInspectorBaseUrl","results","DevToolsPluginCliExtensionExecutor","projectRoot","execute","parsedResults","DevToolsPluginOutputSchema","safeParse","success","Error","error","issues","map","issue","message","join","content","data","line","type","text","level","url","e","Log","toString","isError"],"mappings":";;;;+BASsBA;;;eAAAA;;;sCARqB;oDACQ;kDAEF;qBAC7B;AAEpB,MAAMC,QAAQC,QAAQ,SAAS;AAExB,eAAeF,mBAAmBG,SAAoB,EAAEC,gBAAkC;IAC/F,MAAMC,UAAU,MAAMD,iBAAiBE,qBAAqB,CAACC,iBAAiB;IAE9E,KAAK,MAAMC,UAAUH,QAAS;QAC5B,IAAIG,OAAOC,aAAa,EAAE;YACxB,MAAMC,WAAW,AAACF,CAAAA,OAAOC,aAAa,CAACC,QAAQ,IAAI,EAAE,AAAD,EAAGC,MAAM,CAAC,CAACC;oBAC7DA;wBAAAA,kBAAAA,EAAEC,YAAY,qBAAdD,gBAAgBE,QAAQ,CAAC;;YAE3B,IAAIJ,SAASK,MAAM,KAAK,GAAG;gBACzB;YACF;YAEA,MAAMC,SAASC,IAAAA,kEAAgC,EAACT;YAEhDP,MACE,CAAC,yCAAyC,EAAEO,OAAOU,WAAW,CAAC,SAAS,EAAER,SAASK,MAAM,CAAC,SAAS,CAAC;YAGtGZ,UAAUgB,YAAY,CACpBX,OAAOU,WAAW,EAClB;gBACEE,OAAOZ,OAAOU,WAAW;gBACzBG,aAAab,OAAOa,WAAW;gBAC/BC,aAAa;oBAAEC,YAAYP;gBAAO;YACpC,GACA,OAAO,EAAEO,UAAU,EAAE;gBACnB,IAAI;oBACF,MAAM,EAAEC,OAAO,EAAE,GAAGC,MAAM,GAAGF;oBAE7B,MAAMG,oBAAoBtB,iBACvBuB,mBAAmB,GACnBC,qBAAqB;oBAExB,MAAMC,UAAU,MAAM,IAAIC,sEAAkC,CAC1DtB,QACAJ,iBAAiB2B,WAAW,EAC5BC,OAAO,CAAC;wBAAER;wBAASC;wBAAMC;oBAAkB;oBAE7C,MAAMO,gBAAgBC,gDAA0B,CAACC,SAAS,CAACN;oBAC3D,IAAII,cAAcG,OAAO,KAAK,OAAO;wBACnC,MAAM,IAAIC,MACR,CAAC,iCAAiC,EAAEJ,cAAcK,KAAK,CAACC,MAAM,CAC3DC,GAAG,CAAC,CAACC,QAAUA,MAAMC,OAAO,EAC5BC,IAAI,CAAC,OAAO;oBAEnB;oBACA,OAAO;wBACLC,SAASX,cAAcY,IAAI,CACxBL,GAAG,CAAC,CAACM;4BACJ,MAAM,EAAEC,IAAI,EAAE,GAAGD;4BACjB,IAAIC,SAAS,QAAQ;gCACnB,OAAO;oCAAEA;oCAAMC,MAAMF,KAAKE,IAAI;oCAAEC,OAAOH,KAAKG,KAAK;oCAAEC,KAAKJ,KAAKI,GAAG;gCAAC;4BACnE,OAAO,IAAIJ,KAAKC,IAAI,KAAK,WAAWD,KAAKC,IAAI,KAAK,SAAS;gCACzD,kGAAkG;gCAClG,gDAAgD;gCAChD,OAAO;oCACLA,MAAM;oCACNC,MAAM,GAAGD,KAAK,WAAW,EAAED,KAAKI,GAAG,GAAGJ,KAAKE,IAAI,GAAG,OAAOF,KAAKE,IAAI,GAAG,MAAM,IAAI;gCACjF;4BACF;4BACA,OAAO;wBACT,GACCrC,MAAM,CAAC,CAACmC,OAA6CA,SAAS;oBACnE;gBACF,EAAE,OAAOK,GAAQ;oBACfC,QAAG,CAACd,KAAK,CAAC,oCAAoCa;oBAC9C,OAAO;wBACLP,SAAS;4BAAC;gCAAEG,MAAM;gCAAQC,MAAM,CAAC,yBAAyB,EAAEG,EAAEE,QAAQ,IAAI;4BAAC;yBAAE;wBAC7EC,SAAS;oBACX;gBACF;YACF;QAEJ;IACF;AACF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "createMCPDevToolsExtensionSchema", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return createMCPDevToolsExtensionSchema;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
function _zod() {
|
|
12
|
+
const data = require("zod");
|
|
13
|
+
_zod = function() {
|
|
14
|
+
return data;
|
|
15
|
+
};
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
function createMCPDevToolsExtensionSchema(plugin) {
|
|
19
|
+
var _plugin_cliExtensions;
|
|
20
|
+
if (plugin.cliExtensions == null || ((_plugin_cliExtensions = plugin.cliExtensions) == null ? void 0 : _plugin_cliExtensions.commands.length) === 0) {
|
|
21
|
+
throw new Error(`Plugin ${plugin.packageName} has no commands defined. Please define at least one command.`);
|
|
22
|
+
}
|
|
23
|
+
const commands = plugin.cliExtensions.commands;
|
|
24
|
+
// Build a rich description that explains each command and its parameters
|
|
25
|
+
const commandDescriptions = commands.map((c)=>{
|
|
26
|
+
var _c_parameters;
|
|
27
|
+
const params = (_c_parameters = c.parameters) == null ? void 0 : _c_parameters.map((p)=>p.name).join(', ');
|
|
28
|
+
return params ? `"${c.name}": ${c.title} (params: ${params})` : `"${c.name}": ${c.title}`;
|
|
29
|
+
}).join('. ');
|
|
30
|
+
// Create enum of command names for clear LLM selection
|
|
31
|
+
const commandNames = commands.map((c)=>c.name);
|
|
32
|
+
// Collect all unique parameters across all commands
|
|
33
|
+
// Track which commands use each parameter for documentation
|
|
34
|
+
const parameterCommandMap = {};
|
|
35
|
+
const parameterDescriptions = {};
|
|
36
|
+
for (const command of commands){
|
|
37
|
+
if (command.parameters && command.parameters.length > 0) {
|
|
38
|
+
for (const param of command.parameters){
|
|
39
|
+
if (!parameterCommandMap[param.name]) {
|
|
40
|
+
parameterCommandMap[param.name] = [];
|
|
41
|
+
parameterDescriptions[param.name] = param.description || '';
|
|
42
|
+
}
|
|
43
|
+
parameterCommandMap[param.name].push(command.name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Build parameters with descriptions that indicate which command(s) they belong to
|
|
48
|
+
const allParameters = {};
|
|
49
|
+
for (const [paramName, commandList] of Object.entries(parameterCommandMap)){
|
|
50
|
+
const baseDescription = parameterDescriptions[paramName];
|
|
51
|
+
const commandsUsingParam = commandList.length === commands.length ? 'all commands' : commandList.map((c)=>`"${c}"`).join(', ');
|
|
52
|
+
// Include command context in the description so LLMs know when to use each parameter
|
|
53
|
+
const fullDescription = baseDescription ? `${baseDescription} (Used by: ${commandsUsingParam})` : `Parameter for: ${commandsUsingParam}`;
|
|
54
|
+
allParameters[paramName] = _zod().z.string().optional().describe(fullDescription);
|
|
55
|
+
}
|
|
56
|
+
// Build the command description with clear instructions for the LLM
|
|
57
|
+
const hasParameters = Object.keys(allParameters).length > 0;
|
|
58
|
+
const commandDescription = hasParameters ? `Required. The command to execute. You must select exactly one command from the enum values. ` + `Each command may require specific parameters - only include parameters that belong to the selected command. ` + `Commands: ${commandDescriptions}.` : `Required. The command to execute. Select exactly one from the available options. ` + `Commands: ${commandDescriptions}.`;
|
|
59
|
+
// Build the flat schema with additionalProperties: false for LLM compatibility
|
|
60
|
+
const schema = _zod().z.object({
|
|
61
|
+
command: _zod().z.enum(commandNames).describe(commandDescription),
|
|
62
|
+
...allParameters
|
|
63
|
+
}).strict(); // .strict() adds additionalProperties: false
|
|
64
|
+
return schema;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=createMCPDevToolsExtensionSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/createMCPDevToolsExtensionSchema.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { DevToolsPlugin } from './DevToolsPlugin';\n\n/**\n * Creates an MCP-compatible JSON schema for a DevTools plugin's CLI extensions.\n *\n * LLM agents have varying support for complex JSON schema features like `anyOf`/`oneOf`\n * discriminated unions. This implementation uses a flat schema with an enum for the\n * command name, which provides the best compatibility across different LLM providers:\n *\n * - OpenAI: Supports `anyOf` but requires `additionalProperties: false` and all fields `required`\n * - Claude/Anthropic: Works best with simple flat schemas with enums\n * - Other providers: Generally have limited or inconsistent support for discriminated unions\n *\n * To compensate for the lack of discriminated unions, parameter descriptions include\n * which command(s) they belong to, and command descriptions include their parameters.\n *\n * The resulting schema structure is:\n * ```json\n * {\n * \"type\": \"object\",\n * \"properties\": {\n * \"command\": {\n * \"type\": \"string\",\n * \"enum\": [\"cmd1\", \"cmd2\", ...],\n * \"description\": \"The command to execute. Available commands: \\\"cmd1\\\" - Title 1 (params: foo); ...\"\n * },\n * \"foo\": { \"type\": \"string\", \"description\": \"Foo description (Used by: \\\"cmd1\\\")\" },\n * ...\n * },\n * \"required\": [\"command\"],\n * \"additionalProperties\": false\n * }\n * ```\n */\nexport function createMCPDevToolsExtensionSchema(plugin: DevToolsPlugin) {\n if (plugin.cliExtensions == null || plugin.cliExtensions?.commands.length === 0) {\n throw new Error(\n `Plugin ${plugin.packageName} has no commands defined. Please define at least one command.`\n );\n }\n\n const commands = plugin.cliExtensions.commands;\n\n // Build a rich description that explains each command and its parameters\n const commandDescriptions = commands\n .map((c) => {\n const params = c.parameters?.map((p) => p.name).join(', ');\n return params ? `\"${c.name}\": ${c.title} (params: ${params})` : `\"${c.name}\": ${c.title}`;\n })\n .join('. ');\n\n // Create enum of command names for clear LLM selection\n const commandNames = commands.map((c) => c.name) as [string, ...string[]];\n\n // Collect all unique parameters across all commands\n // Track which commands use each parameter for documentation\n const parameterCommandMap: Record<string, string[]> = {};\n const parameterDescriptions: Record<string, string> = {};\n\n for (const command of commands) {\n if (command.parameters && command.parameters.length > 0) {\n for (const param of command.parameters) {\n if (!parameterCommandMap[param.name]) {\n parameterCommandMap[param.name] = [];\n parameterDescriptions[param.name] = param.description || '';\n }\n parameterCommandMap[param.name].push(command.name);\n }\n }\n }\n\n // Build parameters with descriptions that indicate which command(s) they belong to\n const allParameters: Record<string, z.ZodTypeAny> = {};\n for (const [paramName, commandList] of Object.entries(parameterCommandMap)) {\n const baseDescription = parameterDescriptions[paramName];\n const commandsUsingParam =\n commandList.length === commands.length\n ? 'all commands'\n : commandList.map((c) => `\"${c}\"`).join(', ');\n\n // Include command context in the description so LLMs know when to use each parameter\n const fullDescription = baseDescription\n ? `${baseDescription} (Used by: ${commandsUsingParam})`\n : `Parameter for: ${commandsUsingParam}`;\n\n allParameters[paramName] = z.string().optional().describe(fullDescription);\n }\n\n // Build the command description with clear instructions for the LLM\n const hasParameters = Object.keys(allParameters).length > 0;\n const commandDescription = hasParameters\n ? `Required. The command to execute. You must select exactly one command from the enum values. ` +\n `Each command may require specific parameters - only include parameters that belong to the selected command. ` +\n `Commands: ${commandDescriptions}.`\n : `Required. The command to execute. Select exactly one from the available options. ` +\n `Commands: ${commandDescriptions}.`;\n\n // Build the flat schema with additionalProperties: false for LLM compatibility\n const schema = z\n .object({\n command: z.enum(commandNames).describe(commandDescription),\n ...allParameters,\n })\n .strict(); // .strict() adds additionalProperties: false\n\n return schema;\n}\n"],"names":["createMCPDevToolsExtensionSchema","plugin","cliExtensions","commands","length","Error","packageName","commandDescriptions","map","c","params","parameters","p","name","join","title","commandNames","parameterCommandMap","parameterDescriptions","command","param","description","push","allParameters","paramName","commandList","Object","entries","baseDescription","commandsUsingParam","fullDescription","z","string","optional","describe","hasParameters","keys","commandDescription","schema","object","enum","strict"],"mappings":"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"}
|
|
@@ -15,11 +15,19 @@ function _ws() {
|
|
|
15
15
|
};
|
|
16
16
|
return data;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
const _net = require("../../../utils/net");
|
|
19
|
+
function createDevToolsPluginWebsocketEndpoint({ serverBaseUrl }) {
|
|
19
20
|
const wss = new (_ws()).WebSocketServer({
|
|
20
21
|
noServer: true
|
|
21
22
|
});
|
|
22
|
-
wss.on('connection', (ws)=>{
|
|
23
|
+
wss.on('connection', (ws, request)=>{
|
|
24
|
+
// Explicitly limit devtools websocket to loopback requests
|
|
25
|
+
if (!(0, _net.isLocalSocket)(request.socket) || !(0, _net.isMatchingOrigin)(request, serverBaseUrl)) {
|
|
26
|
+
// NOTE: `socket.close` nicely closes the websocket, which will still allow incoming messages
|
|
27
|
+
// `socket.terminate` instead forcefully closes down the socket
|
|
28
|
+
ws.terminate();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
23
31
|
ws.on('message', (message, isBinary)=>{
|
|
24
32
|
// Broadcast the received message to all other connected clients
|
|
25
33
|
wss.clients.forEach((client)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/start/server/metro/DevToolsPluginWebsocketEndpoint.ts"],"sourcesContent":["import { WebSocket, WebSocketServer } from 'ws';\n\nexport function createDevToolsPluginWebsocketEndpoint(): Record<string, WebSocketServer> {\n const wss = new WebSocketServer({ noServer: true });\n\n wss.on('connection', (ws
|
|
1
|
+
{"version":3,"sources":["../../../../../src/start/server/metro/DevToolsPluginWebsocketEndpoint.ts"],"sourcesContent":["import { WebSocket, WebSocketServer } from 'ws';\n\nimport { isLocalSocket, isMatchingOrigin } from '../../../utils/net';\n\ninterface DevToolsPluginWebsocketEndpointParams {\n serverBaseUrl: string;\n}\n\nexport function createDevToolsPluginWebsocketEndpoint({\n serverBaseUrl,\n}: DevToolsPluginWebsocketEndpointParams): Record<string, WebSocketServer> {\n const wss = new WebSocketServer({ noServer: true });\n\n wss.on('connection', (ws, request) => {\n // Explicitly limit devtools websocket to loopback requests\n if (!isLocalSocket(request.socket) || !isMatchingOrigin(request, serverBaseUrl)) {\n // NOTE: `socket.close` nicely closes the websocket, which will still allow incoming messages\n // `socket.terminate` instead forcefully closes down the socket\n ws.terminate();\n return;\n }\n\n ws.on('message', (message, isBinary) => {\n // Broadcast the received message to all other connected clients\n wss.clients.forEach((client) => {\n if (client !== ws && client.readyState === WebSocket.OPEN) {\n client.send(message, { binary: isBinary });\n }\n });\n });\n });\n\n return { '/expo-dev-plugins/broadcast': wss };\n}\n"],"names":["createDevToolsPluginWebsocketEndpoint","serverBaseUrl","wss","WebSocketServer","noServer","on","ws","request","isLocalSocket","socket","isMatchingOrigin","terminate","message","isBinary","clients","forEach","client","readyState","WebSocket","OPEN","send","binary"],"mappings":";;;;+BAQgBA;;;eAAAA;;;;yBAR2B;;;;;;qBAEK;AAMzC,SAASA,sCAAsC,EACpDC,aAAa,EACyB;IACtC,MAAMC,MAAM,IAAIC,CAAAA,KAAc,iBAAC,CAAC;QAAEC,UAAU;IAAK;IAEjDF,IAAIG,EAAE,CAAC,cAAc,CAACC,IAAIC;QACxB,2DAA2D;QAC3D,IAAI,CAACC,IAAAA,kBAAa,EAACD,QAAQE,MAAM,KAAK,CAACC,IAAAA,qBAAgB,EAACH,SAASN,gBAAgB;YAC/E,6FAA6F;YAC7F,+DAA+D;YAC/DK,GAAGK,SAAS;YACZ;QACF;QAEAL,GAAGD,EAAE,CAAC,WAAW,CAACO,SAASC;YACzB,gEAAgE;YAChEX,IAAIY,OAAO,CAACC,OAAO,CAAC,CAACC;gBACnB,IAAIA,WAAWV,MAAMU,OAAOC,UAAU,KAAKC,eAAS,CAACC,IAAI,EAAE;oBACzDH,OAAOI,IAAI,CAACR,SAAS;wBAAES,QAAQR;oBAAS;gBAC1C;YACF;QACF;IACF;IAEA,OAAO;QAAE,+BAA+BX;IAAI;AAC9C"}
|
|
@@ -102,7 +102,6 @@ const _getStaticRenderFunctions = require("../getStaticRenderFunctions");
|
|
|
102
102
|
const _resolveLoader = require("./resolveLoader");
|
|
103
103
|
const _ContextModuleSourceMapsMiddleware = require("../middleware/ContextModuleSourceMapsMiddleware");
|
|
104
104
|
const _CreateFileMiddleware = require("../middleware/CreateFileMiddleware");
|
|
105
|
-
const _DataLoaderModuleMiddleware = require("../middleware/DataLoaderModuleMiddleware");
|
|
106
105
|
const _DevToolsPluginMiddleware = require("../middleware/DevToolsPluginMiddleware");
|
|
107
106
|
const _DomComponentsMiddleware = require("../middleware/DomComponentsMiddleware");
|
|
108
107
|
const _FaviconMiddleware = require("../middleware/FaviconMiddleware");
|
|
@@ -285,6 +284,50 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
285
284
|
files
|
|
286
285
|
};
|
|
287
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Bundle render module for use in SSR
|
|
289
|
+
*/ async exportExpoRouterRenderModuleAsync({ files, includeSourceMaps, platform = 'web' }) {
|
|
290
|
+
const renderModule = await this.ssrLoadModuleContents('@expo/router-server/node/render.js', {
|
|
291
|
+
environment: 'node',
|
|
292
|
+
platform
|
|
293
|
+
});
|
|
294
|
+
await this.exportServerRouteAsync({
|
|
295
|
+
contents: renderModule,
|
|
296
|
+
artifactFilename: '_expo/server/render.js',
|
|
297
|
+
files,
|
|
298
|
+
includeSourceMaps,
|
|
299
|
+
descriptor: {
|
|
300
|
+
// ssrRenderModule: true,
|
|
301
|
+
targetDomain: 'server'
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
return files;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Export loader bundles as standalone JS files for SSR data loading.
|
|
308
|
+
*
|
|
309
|
+
* Each loader bundle contains only the `loader` export from the route file,
|
|
310
|
+
* with all other exports (default, named) stripped out by the Babel plugin.
|
|
311
|
+
* This keeps loader bundles small for efficient server-side execution.
|
|
312
|
+
*/ async exportExpoRouterLoadersAsync({ platform, entryPoints, files, outputDir, includeSourceMaps }) {
|
|
313
|
+
// NOTE(@hassankhan): Should we parallelize loader bundling?
|
|
314
|
+
for (const entry of entryPoints){
|
|
315
|
+
const contents = await this.bundleLoader(entry.file, {
|
|
316
|
+
platform
|
|
317
|
+
});
|
|
318
|
+
const pagePath = entry.page.startsWith('/') ? entry.page.slice(1) : entry.page;
|
|
319
|
+
const artifactFilename = (0, _metroOptions.convertPathToModuleSpecifier)(_path().default.join(outputDir, pagePath + '.js'));
|
|
320
|
+
await this.exportServerRouteAsync({
|
|
321
|
+
contents,
|
|
322
|
+
artifactFilename,
|
|
323
|
+
files,
|
|
324
|
+
includeSourceMaps,
|
|
325
|
+
descriptor: {
|
|
326
|
+
loaderId: entry.page
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
288
331
|
async getExpoRouterRoutesManifestAsync({ appDir }) {
|
|
289
332
|
var _exp_extra;
|
|
290
333
|
// getBuiltTimeServerManifest
|
|
@@ -320,7 +363,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
320
363
|
/**
|
|
321
364
|
* This function is invoked when exporting via `expo export`
|
|
322
365
|
*/ async getStaticRenderFunctionAsync() {
|
|
323
|
-
var _exp_extra, _exp_extra1;
|
|
366
|
+
var _exp_extra_router, _exp_extra, _exp_web, _exp_extra1, _exp_extra2;
|
|
324
367
|
const { routerRoot } = this.instanceMetroOptions;
|
|
325
368
|
(0, _assert().default)(routerRoot != null, 'The server must be started before calling getStaticRenderFunctionAsync.');
|
|
326
369
|
const appDir = _path().default.join(this.projectRoot, routerRoot);
|
|
@@ -331,15 +374,19 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
331
374
|
environment: 'node'
|
|
332
375
|
});
|
|
333
376
|
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
377
|
+
const useServerRendering = ((_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerRendering) ?? false;
|
|
378
|
+
const isExportingWithSSR = ((_exp_web = exp.web) == null ? void 0 : _exp_web.output) === 'server' && useServerRendering && !this.isReactServerComponentsEnabled;
|
|
334
379
|
const serverManifest = await getBuildTimeServerManifestAsync({
|
|
335
|
-
...(
|
|
380
|
+
...(_exp_extra1 = exp.extra) == null ? void 0 : _exp_extra1.router,
|
|
381
|
+
// Skip static params expansion in SSR mode, routes are matched at runtime instead
|
|
382
|
+
skipStaticParams: isExportingWithSSR
|
|
336
383
|
});
|
|
337
384
|
return {
|
|
338
385
|
serverManifest,
|
|
339
386
|
// Get routes from Expo Router.
|
|
340
387
|
manifest: await getManifest({
|
|
341
388
|
preserveApiRoutes: false,
|
|
342
|
-
...(
|
|
389
|
+
...(_exp_extra2 = exp.extra) == null ? void 0 : _exp_extra2.router
|
|
343
390
|
}),
|
|
344
391
|
// Get route generating function
|
|
345
392
|
renderAsync: async (path, route, opts)=>{
|
|
@@ -355,7 +402,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
355
402
|
if (!resolvedLoaderRoute) {
|
|
356
403
|
return undefined;
|
|
357
404
|
}
|
|
358
|
-
return
|
|
405
|
+
return this.executeServerDataLoaderAsync(location, resolvedLoaderRoute);
|
|
359
406
|
}
|
|
360
407
|
};
|
|
361
408
|
}
|
|
@@ -385,7 +432,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
385
432
|
}
|
|
386
433
|
/**
|
|
387
434
|
* This function is invoked when running in development via `expo start`
|
|
388
|
-
*/ async getStaticPageAsync(pathname, route) {
|
|
435
|
+
*/ async getStaticPageAsync(pathname, route, request) {
|
|
389
436
|
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
390
437
|
const { mode, isExporting, clientBoundaries, baseUrl, reactCompiler, routerRoot, asyncRoutes } = this.instanceMetroOptions;
|
|
391
438
|
(0, _assert().default)(mode != null && isExporting != null && baseUrl != null && reactCompiler != null && routerRoot != null && asyncRoutes != null, 'The server must be started before calling getStaticPageAsync.');
|
|
@@ -426,10 +473,13 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
426
473
|
if (!resolvedLoaderRoute) {
|
|
427
474
|
return await getStaticContent(location);
|
|
428
475
|
}
|
|
429
|
-
const
|
|
476
|
+
const loaderResult = await this.executeServerDataLoaderAsync(location, resolvedLoaderRoute, request);
|
|
477
|
+
if (!loaderResult) {
|
|
478
|
+
return await getStaticContent(location);
|
|
479
|
+
}
|
|
430
480
|
return await getStaticContent(location, {
|
|
431
481
|
loader: {
|
|
432
|
-
data
|
|
482
|
+
data: loaderResult.data
|
|
433
483
|
}
|
|
434
484
|
});
|
|
435
485
|
};
|
|
@@ -857,18 +907,6 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
857
907
|
});
|
|
858
908
|
// Append support for redirecting unhandled requests to the index.html page on web.
|
|
859
909
|
if (this.isTargetingWeb()) {
|
|
860
|
-
var _exp_extra_router1, _exp_extra2;
|
|
861
|
-
if ((_exp_extra2 = exp.extra) == null ? void 0 : (_exp_extra_router1 = _exp_extra2.router) == null ? void 0 : _exp_extra_router1.unstable_useServerDataLoaders) {
|
|
862
|
-
const loaderModuleMiddleware = new _DataLoaderModuleMiddleware.DataLoaderModuleMiddleware(this.projectRoot, appDir, async (location, route)=>{
|
|
863
|
-
const resolvedLoaderRoute = (0, _resolveLoader.fromServerManifestRoute)(location.pathname, route);
|
|
864
|
-
if (!resolvedLoaderRoute) {
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
return this.executeServerDataLoaderAsync(location, resolvedLoaderRoute);
|
|
868
|
-
}, ()=>this.getDevServerUrlOrAssert());
|
|
869
|
-
// This MUST be before ServeStaticMiddleware so it doesn't treat the loader files as static assets
|
|
870
|
-
middleware.use(loaderModuleMiddleware.getHandler());
|
|
871
|
-
}
|
|
872
910
|
// This MUST be after the manifest middleware so it doesn't have a chance to serve the template `public/index.html`.
|
|
873
911
|
middleware.use(new _ServeStaticMiddleware.ServeStaticMiddleware(this.projectRoot).getHandler());
|
|
874
912
|
// This should come after the static middleware so it doesn't serve the favicon from `public/favicon.ico`.
|
|
@@ -940,7 +978,19 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
940
978
|
bundleApiRoute: (functionFilePath)=>this.ssrImportApiRoute(functionFilePath, {
|
|
941
979
|
platform: 'web'
|
|
942
980
|
}),
|
|
943
|
-
|
|
981
|
+
executeLoaderAsync: async (route, request)=>{
|
|
982
|
+
var _exp_web, _exp_extra_router, _exp_extra;
|
|
983
|
+
const url = new URL(request.url);
|
|
984
|
+
const resolvedLoaderRoute = (0, _resolveLoader.fromServerManifestRoute)(url.pathname, route);
|
|
985
|
+
if (!resolvedLoaderRoute) {
|
|
986
|
+
return undefined;
|
|
987
|
+
}
|
|
988
|
+
// Only pass the request in SSR mode (server output with SSR enabled).
|
|
989
|
+
// In static mode, loaders should not receive request data.
|
|
990
|
+
const isSSREnabled = ((_exp_web = exp.web) == null ? void 0 : _exp_web.output) === 'server' && ((_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerRendering) === true;
|
|
991
|
+
return this.executeServerDataLoaderAsync(url, resolvedLoaderRoute, isSSREnabled ? request : undefined);
|
|
992
|
+
},
|
|
993
|
+
getStaticPageAsync: async (pathname, route, request)=>{
|
|
944
994
|
// TODO: Add server rendering when RSC is enabled.
|
|
945
995
|
if (isReactServerComponentsEnabled) {
|
|
946
996
|
// NOTE: This is a temporary hack to return the SPA/template index.html in development when RSC is enabled.
|
|
@@ -951,7 +1001,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
951
1001
|
};
|
|
952
1002
|
}
|
|
953
1003
|
// Non-RSC apps will bundle the static HTML for a given pathname and respond with it.
|
|
954
|
-
return this.getStaticPageAsync(pathname, route);
|
|
1004
|
+
return this.getStaticPageAsync(pathname, route, request);
|
|
955
1005
|
}
|
|
956
1006
|
}));
|
|
957
1007
|
}
|
|
@@ -1183,13 +1233,15 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1183
1233
|
this.pendingRouteOperations.clear();
|
|
1184
1234
|
}
|
|
1185
1235
|
/**
|
|
1186
|
-
* Execute a route's loader function. Used during
|
|
1236
|
+
* Execute a route's loader function. Used during development and SSG to fetch data required by
|
|
1237
|
+
* routes.
|
|
1187
1238
|
*
|
|
1188
1239
|
* This function is used during development and production builds, and **must** receive a valid
|
|
1189
1240
|
* matched route.
|
|
1190
1241
|
*
|
|
1191
1242
|
* @experimental
|
|
1192
|
-
*/ async executeServerDataLoaderAsync(location, route
|
|
1243
|
+
*/ async executeServerDataLoaderAsync(location, route, // The `request` object is only available when using SSR
|
|
1244
|
+
request) {
|
|
1193
1245
|
var _exp_extra;
|
|
1194
1246
|
const { exp } = (0, _config().getConfig)(this.projectRoot);
|
|
1195
1247
|
const { unstable_useServerDataLoaders } = (_exp_extra = exp.extra) == null ? void 0 : _exp_extra.router;
|
|
@@ -1198,7 +1250,6 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1198
1250
|
}
|
|
1199
1251
|
const { routerRoot } = this.instanceMetroOptions;
|
|
1200
1252
|
(0, _assert().default)(routerRoot != null, 'The server must be started before calling executeRouteLoaderAsync.');
|
|
1201
|
-
let loaderData;
|
|
1202
1253
|
try {
|
|
1203
1254
|
debug(`Matched ${location.pathname} to file: ${route.file}`);
|
|
1204
1255
|
const appDir = _path().default.join(this.projectRoot, routerRoot);
|
|
@@ -1207,22 +1258,43 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1207
1258
|
modulePath = modulePath.replace(/\.(js|ts)x?$/, '');
|
|
1208
1259
|
debug('Using loader module path: ', modulePath);
|
|
1209
1260
|
const routeModule = await this.ssrLoadModule(modulePath, {
|
|
1210
|
-
environment: 'node'
|
|
1261
|
+
environment: 'node',
|
|
1262
|
+
isLoaderBundle: true
|
|
1211
1263
|
});
|
|
1212
1264
|
if (routeModule.loader) {
|
|
1213
1265
|
// Register this module for loader HMR
|
|
1214
1266
|
this.setupLoaderHmr(modulePath);
|
|
1215
|
-
|
|
1267
|
+
const data = await routeModule.loader({
|
|
1216
1268
|
params: route.params,
|
|
1217
|
-
|
|
1218
|
-
request: null
|
|
1269
|
+
request
|
|
1219
1270
|
});
|
|
1271
|
+
const normalizedData = data === undefined ? {} : data;
|
|
1272
|
+
debug('Loader data:', normalizedData, ' for location:', location.pathname);
|
|
1273
|
+
return {
|
|
1274
|
+
data: normalizedData
|
|
1275
|
+
};
|
|
1220
1276
|
}
|
|
1277
|
+
debug('No loader found for location:', location.pathname);
|
|
1278
|
+
return undefined;
|
|
1221
1279
|
} catch (error) {
|
|
1222
1280
|
throw new _errors.CommandError('LOADER_EXECUTION_FAILED', `Failed to execute loader for route "${location.pathname}": ${error.message}`);
|
|
1223
1281
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Bundle a loader module with Metro and return the string contents.
|
|
1285
|
+
*/ async bundleLoader(filePath, { platform }) {
|
|
1286
|
+
try {
|
|
1287
|
+
debug('Bundle loader:', filePath);
|
|
1288
|
+
return await this.ssrLoadModuleContents(filePath, {
|
|
1289
|
+
isExporting: this.instanceMetroOptions.isExporting,
|
|
1290
|
+
platform,
|
|
1291
|
+
environment: 'node',
|
|
1292
|
+
isLoaderBundle: true
|
|
1293
|
+
});
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
debug('Failed to bundle loader:', filePath, ':', error.message);
|
|
1296
|
+
throw new _errors.CommandError('LOADER_BUNDLE', (0, _chalk().default)`Failed to bundle loader: {bold ${filePath}}\n\n` + error.message);
|
|
1297
|
+
}
|
|
1226
1298
|
}
|
|
1227
1299
|
// Ensure the global is available for SSR CSS modules to inject client updates.
|
|
1228
1300
|
bindRSCDevModuleInjectionHandler() {
|