@expo/cli 56.1.4 → 56.1.6
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/api/user/actions.js +7 -0
- package/build/src/api/user/actions.js.map +1 -1
- package/build/src/api/user/expoSsoLauncher.js +2 -8
- package/build/src/api/user/expoSsoLauncher.js.map +1 -1
- package/build/src/api/user/user.js +12 -0
- package/build/src/api/user/user.js.map +1 -1
- package/build/src/events/index.js +1 -1
- package/build/src/export/embed/exportEmbedAsync.js +1 -1
- package/build/src/export/embed/exportEmbedAsync.js.map +1 -1
- package/build/src/export/embed/exportServer.js +1 -1
- package/build/src/export/embed/exportServer.js.map +1 -1
- package/build/src/export/exportApp.js +1 -1
- package/build/src/export/exportApp.js.map +1 -1
- package/build/src/export/publicFolder.js +19 -1
- package/build/src/export/publicFolder.js.map +1 -1
- package/build/src/login/index.js +25 -5
- package/build/src/login/index.js.map +1 -1
- package/build/src/run/android/resolveLaunchProps.js +4 -1
- package/build/src/run/android/resolveLaunchProps.js.map +1 -1
- package/build/src/start/doctor/dependencies/reactNativeTv.js +149 -0
- package/build/src/start/doctor/dependencies/reactNativeTv.js.map +1 -0
- package/build/src/start/doctor/dependencies/validateDependenciesVersions.js +28 -3
- package/build/src/start/doctor/dependencies/validateDependenciesVersions.js.map +1 -1
- package/build/src/start/platforms/ios/simctl.js +4 -0
- package/build/src/start/platforms/ios/simctl.js.map +1 -1
- package/build/src/start/server/DevToolsPlugin.js +26 -1
- package/build/src/start/server/DevToolsPlugin.js.map +1 -1
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +57 -22
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -1
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js +29 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js.map +1 -1
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js +15 -5
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js.map +1 -1
- package/build/src/start/server/UrlCreator.js +4 -0
- package/build/src/start/server/UrlCreator.js.map +1 -1
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js +13 -1
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +95 -32
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/createServerComponentsMiddleware.js +13 -13
- package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
- package/build/src/start/server/metro/dev-server/createMessageSocket.js +13 -2
- package/build/src/start/server/metro/dev-server/createMessageSocket.js.map +1 -1
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js +2 -1
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js.map +1 -1
- package/build/src/start/server/metro/instantiateMetro.js +5 -4
- package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
- package/build/src/start/server/metro/router.js +10 -1
- package/build/src/start/server/metro/router.js.map +1 -1
- package/build/src/start/server/metro/withMetroMultiPlatform.js +8 -4
- package/build/src/start/server/metro/withMetroMultiPlatform.js.map +1 -1
- package/build/src/start/server/middleware/OpenMiddleware.js +150 -0
- package/build/src/start/server/middleware/OpenMiddleware.js.map +1 -0
- package/build/src/start/server/middleware/RuntimeRedirectMiddleware.js +13 -4
- package/build/src/start/server/middleware/RuntimeRedirectMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/ServeStaticMiddleware.js +2 -9
- package/build/src/start/server/middleware/ServeStaticMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/openHandlers.js +157 -0
- package/build/src/start/server/middleware/openHandlers.js.map +1 -0
- package/build/src/start/server/type-generation/routes.js +1 -3
- package/build/src/start/server/type-generation/routes.js.map +1 -1
- package/build/src/start/server/webTemplate.js +3 -5
- package/build/src/start/server/webTemplate.js.map +1 -1
- package/build/src/utils/net.js +7 -1
- package/build/src/utils/net.js.map +1 -1
- package/build/src/utils/open.js +243 -11
- package/build/src/utils/open.js.map +1 -1
- package/build/src/utils/tar.js +2 -2
- package/build/src/utils/tar.js.map +1 -1
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +17 -18
- package/static/loading-page/index.html +35 -1
|
@@ -136,6 +136,10 @@ class UrlCreator {
|
|
|
136
136
|
getDefaultRouteAddress() {
|
|
137
137
|
return this.gatewayInfo.address;
|
|
138
138
|
}
|
|
139
|
+
/** URL scheme configured for development-build deep links (e.g. `myapp`). `null` when unset. */ getScheme() {
|
|
140
|
+
var _this_defaults;
|
|
141
|
+
return ((_this_defaults = this.defaults) == null ? void 0 : _this_defaults.scheme) ?? null;
|
|
142
|
+
}
|
|
139
143
|
/** Get the URL components from the Ngrok server URL. */ getTunnelUrlComponents(options) {
|
|
140
144
|
const tunnelUrl = this.bundlerInfo.getTunnelUrl == null ? void 0 : this.bundlerInfo.getTunnelUrl.call(this.bundlerInfo);
|
|
141
145
|
if (!tunnelUrl) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/UrlCreator.ts"],"sourcesContent":["import assert from 'assert';\nimport { URL } from 'url';\n\nimport * as Log from '../../log';\nimport type { GatewayInfo } from '../../utils/ip';\nimport { getGateway, getGatewayAsync } from '../../utils/ip';\n\nconst debug = require('debug')('expo:start:server:urlCreator') as typeof console.log;\n\nexport interface CreateURLOptions {\n /** URL scheme to use when opening apps in custom runtimes. */\n scheme?: string | null;\n /** Type of dev server host to use. */\n hostType?: 'localhost' | 'lan' | 'tunnel';\n /** Requested hostname. */\n hostname?: string | null;\n}\n\ninterface UrlComponents {\n port: string;\n hostname: string;\n protocol: string;\n}\n\ninterface BundlerInfo {\n port: number;\n getTunnelUrl?(): string | null;\n}\n\nexport class UrlCreator {\n constructor(\n public defaults: CreateURLOptions,\n private bundlerInfo: BundlerInfo,\n private gatewayInfo: GatewayInfo = getGateway()\n ) {}\n\n static async init(defaults: CreateURLOptions | undefined | null, bundlerInfo: BundlerInfo) {\n const gatewayInfo = await getGatewayAsync();\n return new UrlCreator(defaults || {}, bundlerInfo, gatewayInfo);\n }\n\n /**\n * Return a URL for the \"loading\" interstitial page that is used to disambiguate which\n * native runtime to open the dev server with.\n *\n * @param options options for creating the URL\n * @param platform when opening the URL from the CLI to a connected device we can specify the platform as a query parameter, otherwise it will be inferred from the unsafe user agent sniffing.\n *\n * @returns URL like `http://localhost:8081/_expo/loading?platform=ios`\n * @returns URL like `http://localhost:8081/_expo/loading` when no platform is provided.\n */\n public constructLoadingUrl(options: CreateURLOptions, platform: string | null): string {\n const url = new URL('_expo/loading', this.constructUrl({ scheme: 'http', ...options }));\n if (platform) {\n url.search = new URLSearchParams({ platform }).toString();\n }\n const loadingUrl = url.toString();\n debug(`Loading URL: ${loadingUrl}`);\n return loadingUrl;\n }\n\n /** Create a URI for launching in a native dev client. Returns `null` when no `scheme` can be resolved. */\n public constructDevClientUrl(options?: CreateURLOptions): null | string {\n const protocol = options?.scheme || this.defaults?.scheme;\n\n if (\n !protocol ||\n // Prohibit the use of http(s) in dev client URIs since they'll never be valid.\n ['http', 'https'].includes(protocol.toLowerCase()) ||\n // Prohibit the use of `_` characters in the protocol, Node will throw an error when parsing these URLs\n protocol.includes('_')\n ) {\n debug(`Invalid protocol for dev client URL: ${protocol}`);\n return null;\n }\n\n const manifestUrl = this.constructUrl({\n ...options,\n scheme: this.defaults?.hostType === 'tunnel' ? 'https' : 'http',\n });\n const devClientUrl = `${protocol}://expo-development-client/?url=${encodeURIComponent(\n manifestUrl\n )}`;\n debug(`Dev client URL: ${devClientUrl} -- manifestUrl: ${manifestUrl} -- %O`, options);\n return devClientUrl;\n }\n\n /** Create a generic URL. */\n public constructUrl(options?: Partial<CreateURLOptions> | null): string {\n const urlComponents = this.getUrlComponents({\n ...this.defaults,\n ...options,\n });\n const url = joinUrlComponents(urlComponents);\n debug(`URL: ${url}`);\n return url;\n }\n\n public getDefaultRouteAddress(): string {\n return this.gatewayInfo.address;\n }\n\n /** Get the URL components from the Ngrok server URL. */\n private getTunnelUrlComponents(options: Pick<CreateURLOptions, 'scheme'>): UrlComponents | null {\n const tunnelUrl = this.bundlerInfo.getTunnelUrl?.();\n if (!tunnelUrl) {\n return null;\n }\n const parsed = new URL(tunnelUrl);\n return {\n port: parsed.port,\n hostname: parsed.hostname,\n protocol: options.scheme ?? 'http',\n };\n }\n\n private getUrlComponents(options: CreateURLOptions): UrlComponents {\n // Proxy comes first.\n const proxyURL = getProxyUrl();\n if (proxyURL) {\n return getUrlComponentsFromProxyUrl(options, proxyURL);\n }\n\n // Ngrok.\n if (options.hostType === 'tunnel') {\n const components = this.getTunnelUrlComponents(options);\n if (components) {\n return components;\n }\n Log.warn('Tunnel URL not found (it might not be ready yet), falling back to LAN URL.');\n } else if (options.hostType === 'localhost' && !options.hostname) {\n options.hostname = 'localhost';\n }\n\n return {\n hostname: getDefaultHostname(options, this.gatewayInfo),\n port: this.bundlerInfo.port.toString(),\n protocol: options.scheme ?? 'http',\n };\n }\n}\n\nfunction getUrlComponentsFromProxyUrl(\n options: Pick<CreateURLOptions, 'scheme'>,\n url: string\n): UrlComponents {\n const parsedProxyUrl = new URL(url);\n let protocol = options.scheme ?? 'http';\n if (parsedProxyUrl.protocol === 'https:') {\n if (protocol === 'http') {\n protocol = 'https';\n }\n if (!parsedProxyUrl.port) {\n parsedProxyUrl.port = '443';\n }\n }\n return {\n port: parsedProxyUrl.port,\n hostname: parsedProxyUrl.hostname,\n protocol,\n };\n}\n\nconst getDefaultHostname = (options: CreateURLOptions, gateway: GatewayInfo) => {\n // TODO: Drop REACT_NATIVE_PACKAGER_HOSTNAME\n if (process.env.REACT_NATIVE_PACKAGER_HOSTNAME) {\n return process.env.REACT_NATIVE_PACKAGER_HOSTNAME.trim();\n } else if (options.hostname === 'localhost') {\n // NOTE: We always convert \"localhost\" as a request to 127.0.0.1,\n // to normalize to an address that's consistent\n return '127.0.0.1';\n } else {\n // Fall back to local address\n return options.hostname || gateway.address;\n }\n};\n\nfunction joinUrlComponents({ protocol, hostname, port }: Partial<UrlComponents>): string {\n assert(hostname, 'hostname cannot be inferred.');\n const validProtocol = protocol ? `${protocol}://` : '';\n\n const url = `${validProtocol}${hostname}`;\n\n if (port) {\n return url + `:${port}`;\n }\n\n return url;\n}\n\n/** @deprecated */\nfunction getProxyUrl(): string | undefined {\n return process.env.EXPO_PACKAGER_PROXY_URL;\n}\n\n// TODO: Drop the undocumented env variables:\n// REACT_NATIVE_PACKAGER_HOSTNAME\n// EXPO_PACKAGER_PROXY_URL\n"],"names":["UrlCreator","debug","require","defaults","bundlerInfo","gatewayInfo","getGateway","init","getGatewayAsync","constructLoadingUrl","options","platform","url","URL","constructUrl","scheme","search","URLSearchParams","toString","loadingUrl","constructDevClientUrl","protocol","includes","toLowerCase","manifestUrl","hostType","devClientUrl","encodeURIComponent","urlComponents","getUrlComponents","joinUrlComponents","getDefaultRouteAddress","address","getTunnelUrlComponents","tunnelUrl","getTunnelUrl","parsed","port","hostname","proxyURL","getProxyUrl","getUrlComponentsFromProxyUrl","components","Log","warn","getDefaultHostname","parsedProxyUrl","gateway","process","env","REACT_NATIVE_PACKAGER_HOSTNAME","trim","assert","validProtocol","EXPO_PACKAGER_PROXY_URL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/UrlCreator.ts"],"sourcesContent":["import assert from 'assert';\nimport { URL } from 'url';\n\nimport * as Log from '../../log';\nimport type { GatewayInfo } from '../../utils/ip';\nimport { getGateway, getGatewayAsync } from '../../utils/ip';\n\nconst debug = require('debug')('expo:start:server:urlCreator') as typeof console.log;\n\nexport interface CreateURLOptions {\n /** URL scheme to use when opening apps in custom runtimes. */\n scheme?: string | null;\n /** Type of dev server host to use. */\n hostType?: 'localhost' | 'lan' | 'tunnel';\n /** Requested hostname. */\n hostname?: string | null;\n}\n\ninterface UrlComponents {\n port: string;\n hostname: string;\n protocol: string;\n}\n\ninterface BundlerInfo {\n port: number;\n getTunnelUrl?(): string | null;\n}\n\nexport class UrlCreator {\n constructor(\n public defaults: CreateURLOptions,\n private bundlerInfo: BundlerInfo,\n private gatewayInfo: GatewayInfo = getGateway()\n ) {}\n\n static async init(defaults: CreateURLOptions | undefined | null, bundlerInfo: BundlerInfo) {\n const gatewayInfo = await getGatewayAsync();\n return new UrlCreator(defaults || {}, bundlerInfo, gatewayInfo);\n }\n\n /**\n * Return a URL for the \"loading\" interstitial page that is used to disambiguate which\n * native runtime to open the dev server with.\n *\n * @param options options for creating the URL\n * @param platform when opening the URL from the CLI to a connected device we can specify the platform as a query parameter, otherwise it will be inferred from the unsafe user agent sniffing.\n *\n * @returns URL like `http://localhost:8081/_expo/loading?platform=ios`\n * @returns URL like `http://localhost:8081/_expo/loading` when no platform is provided.\n */\n public constructLoadingUrl(options: CreateURLOptions, platform: string | null): string {\n const url = new URL('_expo/loading', this.constructUrl({ scheme: 'http', ...options }));\n if (platform) {\n url.search = new URLSearchParams({ platform }).toString();\n }\n const loadingUrl = url.toString();\n debug(`Loading URL: ${loadingUrl}`);\n return loadingUrl;\n }\n\n /** Create a URI for launching in a native dev client. Returns `null` when no `scheme` can be resolved. */\n public constructDevClientUrl(options?: CreateURLOptions): null | string {\n const protocol = options?.scheme || this.defaults?.scheme;\n\n if (\n !protocol ||\n // Prohibit the use of http(s) in dev client URIs since they'll never be valid.\n ['http', 'https'].includes(protocol.toLowerCase()) ||\n // Prohibit the use of `_` characters in the protocol, Node will throw an error when parsing these URLs\n protocol.includes('_')\n ) {\n debug(`Invalid protocol for dev client URL: ${protocol}`);\n return null;\n }\n\n const manifestUrl = this.constructUrl({\n ...options,\n scheme: this.defaults?.hostType === 'tunnel' ? 'https' : 'http',\n });\n const devClientUrl = `${protocol}://expo-development-client/?url=${encodeURIComponent(\n manifestUrl\n )}`;\n debug(`Dev client URL: ${devClientUrl} -- manifestUrl: ${manifestUrl} -- %O`, options);\n return devClientUrl;\n }\n\n /** Create a generic URL. */\n public constructUrl(options?: Partial<CreateURLOptions> | null): string {\n const urlComponents = this.getUrlComponents({\n ...this.defaults,\n ...options,\n });\n const url = joinUrlComponents(urlComponents);\n debug(`URL: ${url}`);\n return url;\n }\n\n public getDefaultRouteAddress(): string {\n return this.gatewayInfo.address;\n }\n\n /** URL scheme configured for development-build deep links (e.g. `myapp`). `null` when unset. */\n public getScheme(): string | null {\n return this.defaults?.scheme ?? null;\n }\n\n /** Get the URL components from the Ngrok server URL. */\n private getTunnelUrlComponents(options: Pick<CreateURLOptions, 'scheme'>): UrlComponents | null {\n const tunnelUrl = this.bundlerInfo.getTunnelUrl?.();\n if (!tunnelUrl) {\n return null;\n }\n const parsed = new URL(tunnelUrl);\n return {\n port: parsed.port,\n hostname: parsed.hostname,\n protocol: options.scheme ?? 'http',\n };\n }\n\n private getUrlComponents(options: CreateURLOptions): UrlComponents {\n // Proxy comes first.\n const proxyURL = getProxyUrl();\n if (proxyURL) {\n return getUrlComponentsFromProxyUrl(options, proxyURL);\n }\n\n // Ngrok.\n if (options.hostType === 'tunnel') {\n const components = this.getTunnelUrlComponents(options);\n if (components) {\n return components;\n }\n Log.warn('Tunnel URL not found (it might not be ready yet), falling back to LAN URL.');\n } else if (options.hostType === 'localhost' && !options.hostname) {\n options.hostname = 'localhost';\n }\n\n return {\n hostname: getDefaultHostname(options, this.gatewayInfo),\n port: this.bundlerInfo.port.toString(),\n protocol: options.scheme ?? 'http',\n };\n }\n}\n\nfunction getUrlComponentsFromProxyUrl(\n options: Pick<CreateURLOptions, 'scheme'>,\n url: string\n): UrlComponents {\n const parsedProxyUrl = new URL(url);\n let protocol = options.scheme ?? 'http';\n if (parsedProxyUrl.protocol === 'https:') {\n if (protocol === 'http') {\n protocol = 'https';\n }\n if (!parsedProxyUrl.port) {\n parsedProxyUrl.port = '443';\n }\n }\n return {\n port: parsedProxyUrl.port,\n hostname: parsedProxyUrl.hostname,\n protocol,\n };\n}\n\nconst getDefaultHostname = (options: CreateURLOptions, gateway: GatewayInfo) => {\n // TODO: Drop REACT_NATIVE_PACKAGER_HOSTNAME\n if (process.env.REACT_NATIVE_PACKAGER_HOSTNAME) {\n return process.env.REACT_NATIVE_PACKAGER_HOSTNAME.trim();\n } else if (options.hostname === 'localhost') {\n // NOTE: We always convert \"localhost\" as a request to 127.0.0.1,\n // to normalize to an address that's consistent\n return '127.0.0.1';\n } else {\n // Fall back to local address\n return options.hostname || gateway.address;\n }\n};\n\nfunction joinUrlComponents({ protocol, hostname, port }: Partial<UrlComponents>): string {\n assert(hostname, 'hostname cannot be inferred.');\n const validProtocol = protocol ? `${protocol}://` : '';\n\n const url = `${validProtocol}${hostname}`;\n\n if (port) {\n return url + `:${port}`;\n }\n\n return url;\n}\n\n/** @deprecated */\nfunction getProxyUrl(): string | undefined {\n return process.env.EXPO_PACKAGER_PROXY_URL;\n}\n\n// TODO: Drop the undocumented env variables:\n// REACT_NATIVE_PACKAGER_HOSTNAME\n// EXPO_PACKAGER_PROXY_URL\n"],"names":["UrlCreator","debug","require","defaults","bundlerInfo","gatewayInfo","getGateway","init","getGatewayAsync","constructLoadingUrl","options","platform","url","URL","constructUrl","scheme","search","URLSearchParams","toString","loadingUrl","constructDevClientUrl","protocol","includes","toLowerCase","manifestUrl","hostType","devClientUrl","encodeURIComponent","urlComponents","getUrlComponents","joinUrlComponents","getDefaultRouteAddress","address","getScheme","getTunnelUrlComponents","tunnelUrl","getTunnelUrl","parsed","port","hostname","proxyURL","getProxyUrl","getUrlComponentsFromProxyUrl","components","Log","warn","getDefaultHostname","parsedProxyUrl","gateway","process","env","REACT_NATIVE_PACKAGER_HOSTNAME","trim","assert","validProtocol","EXPO_PACKAGER_PROXY_URL"],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ function createMCPDevToolsExtensionSchema(plugin) {
|
|
|
33
33
|
// Track which commands use each parameter for documentation
|
|
34
34
|
const parameterCommandMap = {};
|
|
35
35
|
const parameterDescriptions = {};
|
|
36
|
+
const parameterTypes = {};
|
|
36
37
|
for (const command of commands){
|
|
37
38
|
if (command.parameters && command.parameters.length > 0) {
|
|
38
39
|
for (const param of command.parameters){
|
|
@@ -41,6 +42,7 @@ function createMCPDevToolsExtensionSchema(plugin) {
|
|
|
41
42
|
commands = [];
|
|
42
43
|
parameterCommandMap[param.name] = commands;
|
|
43
44
|
parameterDescriptions[param.name] = param.description || '';
|
|
45
|
+
parameterTypes[param.name] = param.type;
|
|
44
46
|
}
|
|
45
47
|
commands.push(command.name);
|
|
46
48
|
}
|
|
@@ -53,7 +55,7 @@ function createMCPDevToolsExtensionSchema(plugin) {
|
|
|
53
55
|
const commandsUsingParam = commandList.length === commands.length ? 'all commands' : commandList.map((c)=>`"${c}"`).join(', ');
|
|
54
56
|
// Include command context in the description so LLMs know when to use each parameter
|
|
55
57
|
const fullDescription = baseDescription ? `${baseDescription} (Used by: ${commandsUsingParam})` : `Parameter for: ${commandsUsingParam}`;
|
|
56
|
-
allParameters[paramName] =
|
|
58
|
+
allParameters[paramName] = paramTypeToZod(parameterTypes[paramName]).optional().describe(fullDescription);
|
|
57
59
|
}
|
|
58
60
|
// Build the command description with clear instructions for the LLM
|
|
59
61
|
const hasParameters = Object.keys(allParameters).length > 0;
|
|
@@ -65,5 +67,15 @@ function createMCPDevToolsExtensionSchema(plugin) {
|
|
|
65
67
|
}).strict(); // .strict() adds additionalProperties: false
|
|
66
68
|
return schema;
|
|
67
69
|
}
|
|
70
|
+
function paramTypeToZod(type) {
|
|
71
|
+
switch(type){
|
|
72
|
+
case 'number':
|
|
73
|
+
return _zod().z.number();
|
|
74
|
+
case 'confirm':
|
|
75
|
+
return _zod().z.boolean();
|
|
76
|
+
case 'text':
|
|
77
|
+
return _zod().z.string();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
68
80
|
|
|
69
81
|
//# sourceMappingURL=createMCPDevToolsExtensionSchema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/createMCPDevToolsExtensionSchema.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/createMCPDevToolsExtensionSchema.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport type { DevToolsPluginCommandParameter, DevToolsPluginInfo } from './DevToolsPlugin.schema';\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: DevToolsPluginInfo) {\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 const parameterTypes: Record<string, DevToolsPluginCommandParameter['type']> = {};\n\n for (const command of commands) {\n if (command.parameters && command.parameters.length > 0) {\n for (const param of command.parameters) {\n let commands = parameterCommandMap[param.name];\n if (!commands) {\n commands = [];\n parameterCommandMap[param.name] = commands;\n parameterDescriptions[param.name] = param.description || '';\n parameterTypes[param.name] = param.type;\n }\n commands.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] = paramTypeToZod(parameterTypes[paramName]!)\n .optional()\n .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\nfunction paramTypeToZod(type: DevToolsPluginCommandParameter['type']) {\n switch (type) {\n case 'number':\n return z.number();\n case 'confirm':\n return z.boolean();\n case 'text':\n return z.string();\n }\n}\n"],"names":["createMCPDevToolsExtensionSchema","plugin","cliExtensions","commands","length","Error","packageName","commandDescriptions","map","c","params","parameters","p","name","join","title","commandNames","parameterCommandMap","parameterDescriptions","parameterTypes","command","param","description","type","push","allParameters","paramName","commandList","Object","entries","baseDescription","commandsUsingParam","fullDescription","paramTypeToZod","optional","describe","hasParameters","keys","commandDescription","schema","z","object","enum","strict","number","boolean","string"],"mappings":"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"}
|
|
@@ -107,6 +107,8 @@ const _errors = require("../../../utils/errors");
|
|
|
107
107
|
const _filePath = require("../../../utils/filePath");
|
|
108
108
|
const _nodeEnv = require("../../../utils/nodeEnv");
|
|
109
109
|
const _port = require("../../../utils/port");
|
|
110
|
+
const _AndroidAppIdResolver = require("../../platforms/android/AndroidAppIdResolver");
|
|
111
|
+
const _AppleAppIdResolver = require("../../platforms/ios/AppleAppIdResolver");
|
|
110
112
|
const _BundlerDevServer = require("../BundlerDevServer");
|
|
111
113
|
const _getStaticRenderFunctions = require("../getStaticRenderFunctions");
|
|
112
114
|
const _resolveLoader = require("./resolveLoader");
|
|
@@ -117,10 +119,12 @@ const _DomComponentsMiddleware = require("../middleware/DomComponentsMiddleware"
|
|
|
117
119
|
const _FaviconMiddleware = require("../middleware/FaviconMiddleware");
|
|
118
120
|
const _HistoryFallbackMiddleware = require("../middleware/HistoryFallbackMiddleware");
|
|
119
121
|
const _InterstitialPageMiddleware = require("../middleware/InterstitialPageMiddleware");
|
|
122
|
+
const _OpenMiddleware = require("../middleware/OpenMiddleware");
|
|
120
123
|
const _RuntimeRedirectMiddleware = require("../middleware/RuntimeRedirectMiddleware");
|
|
121
124
|
const _ServeStaticMiddleware = require("../middleware/ServeStaticMiddleware");
|
|
122
125
|
const _metroOptions = require("../middleware/metroOptions");
|
|
123
126
|
const _mutations = require("../middleware/mutations");
|
|
127
|
+
const _openHandlers = require("../middleware/openHandlers");
|
|
124
128
|
const _startTypescriptTypeGeneration = require("../type-generation/startTypescriptTypeGeneration");
|
|
125
129
|
function _interop_require_default(obj) {
|
|
126
130
|
return obj && obj.__esModule ? obj : {
|
|
@@ -959,6 +963,46 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
959
963
|
}
|
|
960
964
|
});
|
|
961
965
|
middleware.use(deepLinkMiddleware.getHandler());
|
|
966
|
+
const getHostSupport = (platform)=>{
|
|
967
|
+
if (platform === 'ios' && process.platform !== 'darwin') {
|
|
968
|
+
return {
|
|
969
|
+
canOpen: false,
|
|
970
|
+
reason: `iOS simulators require macOS with Xcode installed; this dev server is running on ${process.platform}.`
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
return {
|
|
974
|
+
canOpen: true
|
|
975
|
+
};
|
|
976
|
+
};
|
|
977
|
+
// Read all dev-server state live — pressing `s` in the terminal toggles `isDevClient`
|
|
978
|
+
// and the scheme, and `expo-dev-client` can be installed mid-run (re-resolved by
|
|
979
|
+
// isRedirectPageEnabled on every call).
|
|
980
|
+
const openMiddleware = new _OpenMiddleware.OpenMiddleware(this.projectRoot, {
|
|
981
|
+
serverBaseUrl,
|
|
982
|
+
getHostSupport,
|
|
983
|
+
getInfo: (0, _openHandlers.createInfoHandler)({
|
|
984
|
+
urlCreator: this.getUrlCreator(),
|
|
985
|
+
getIsDevClient: ()=>this.isDevClient,
|
|
986
|
+
getIsRedirectPageEnabled: ()=>this.isRedirectPageEnabled(),
|
|
987
|
+
getAppId: async (platform)=>{
|
|
988
|
+
if (platform === 'web') return null;
|
|
989
|
+
const resolver = platform === 'ios' ? new _AppleAppIdResolver.AppleAppIdResolver(this.projectRoot) : new _AndroidAppIdResolver.AndroidAppIdResolver(this.projectRoot);
|
|
990
|
+
try {
|
|
991
|
+
return await resolver.getAppIdAsync();
|
|
992
|
+
} catch {
|
|
993
|
+
// Surfacing the error would block the dry-run; consumers can detect the missing id
|
|
994
|
+
// from `appId: null` and prompt the user to configure ios.bundleIdentifier /
|
|
995
|
+
// android.package.
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}),
|
|
1000
|
+
open: (0, _openHandlers.createOpen)({
|
|
1001
|
+
getIsDevClient: ()=>this.isDevClient,
|
|
1002
|
+
openPlatformAsync: (target, resolver)=>this.openPlatformAsync(target, resolver)
|
|
1003
|
+
})
|
|
1004
|
+
});
|
|
1005
|
+
middleware.use(openMiddleware.getHandler());
|
|
962
1006
|
const domComponentRenderer = (0, _DomComponentsMiddleware.createDomComponentsMiddleware)({
|
|
963
1007
|
projectRoot: this.projectRoot
|
|
964
1008
|
}, instanceMetroOptions);
|
|
@@ -1000,7 +1044,6 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1000
1044
|
metro,
|
|
1001
1045
|
server
|
|
1002
1046
|
}, ({ changes })=>{
|
|
1003
|
-
var _exp_extra_router, _exp_extra;
|
|
1004
1047
|
if (hasApiRoutes) {
|
|
1005
1048
|
// NOTE(EvanBacon): We aren't sure what files the API routes are using so we'll just invalidate
|
|
1006
1049
|
// aggressively to ensure we always have the latest. The only caching we really get here is for
|
|
@@ -1018,12 +1061,6 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1018
1061
|
}
|
|
1019
1062
|
}
|
|
1020
1063
|
}
|
|
1021
|
-
// Handle loader file changes for HMR
|
|
1022
|
-
if ((_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_router = _exp_extra.router) == null ? void 0 : _exp_extra_router.unstable_useServerDataLoaders) {
|
|
1023
|
-
for (const change of changes.modifiedFiles){
|
|
1024
|
-
this.handleLoaderFileChange(change[0]);
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
1064
|
});
|
|
1028
1065
|
}
|
|
1029
1066
|
// If React 19 is enabled, then add RSC middleware to the dev server.
|
|
@@ -1115,6 +1152,11 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1115
1152
|
this.metro = null;
|
|
1116
1153
|
this.hmrServer = null;
|
|
1117
1154
|
this.ssrHmrClients = new Map();
|
|
1155
|
+
for (const unlisten of this.loaderGraphListeners.values()){
|
|
1156
|
+
unlisten();
|
|
1157
|
+
}
|
|
1158
|
+
this.loaderGraphListeners.clear();
|
|
1159
|
+
this.pendingLoaderInvalidationChangeIds.clear();
|
|
1118
1160
|
callback == null ? void 0 : callback(err);
|
|
1119
1161
|
});
|
|
1120
1162
|
};
|
|
@@ -1348,8 +1390,6 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1348
1390
|
isLoaderBundle: true
|
|
1349
1391
|
});
|
|
1350
1392
|
if (routeModule.loader) {
|
|
1351
|
-
// Register this module for loader HMR
|
|
1352
|
-
this.setupLoaderHmr(modulePath);
|
|
1353
1393
|
const maybeResponse = await routeModule.loader(request, route.params);
|
|
1354
1394
|
let data;
|
|
1355
1395
|
if (maybeResponse instanceof Response) {
|
|
@@ -1426,29 +1466,48 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1426
1466
|
};
|
|
1427
1467
|
this.registerSsrHmrAsync(url.toString(), onReload);
|
|
1428
1468
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1469
|
+
// Subscribe to a loader bundle's Metro graph so we can broadcast `loader-invalidate` and
|
|
1470
|
+
// drop the SSR module eval cache when the loader's dependency graph is dirtied. This avoids
|
|
1471
|
+
// the full-page reload the old stub used and keeps client state across loader edits.
|
|
1472
|
+
setupLoaderGraphListener(graphId, resolvedEntryFilePath, graph) {
|
|
1473
|
+
if (this.loaderGraphListeners.has(graphId) || !this.metro) {
|
|
1431
1474
|
return;
|
|
1432
1475
|
}
|
|
1433
|
-
this.
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
const possibleExtensions = [
|
|
1439
|
-
'.tsx',
|
|
1440
|
-
'.ts',
|
|
1441
|
-
'.jsx',
|
|
1442
|
-
'.js'
|
|
1443
|
-
];
|
|
1444
|
-
const isLoaderFile = possibleExtensions.some((ext)=>changedFilePath === loaderPath + ext || changedFilePath === loaderPath);
|
|
1445
|
-
if (isLoaderFile) {
|
|
1446
|
-
debug('[Loader HMR] Loader file changed, triggering reload:', changedFilePath);
|
|
1447
|
-
this.broadcastMessage('sendDevCommand', {
|
|
1448
|
-
name: 'reload'
|
|
1449
|
-
});
|
|
1476
|
+
const deltaBundler = this.metro.getBundler().getDeltaBundler();
|
|
1477
|
+
const onChange = async (changeEvent)=>{
|
|
1478
|
+
debug('[Loader HMR] Graph change detected for:', resolvedEntryFilePath);
|
|
1479
|
+
if (!this.shouldBroadcastLoaderInvalidation(changeEvent == null ? void 0 : changeEvent.changeId)) {
|
|
1480
|
+
return;
|
|
1450
1481
|
}
|
|
1482
|
+
if (typeof globalThis.__c === 'function') {
|
|
1483
|
+
globalThis.__c();
|
|
1484
|
+
}
|
|
1485
|
+
this.broadcastMessage('sendDevCommand', {
|
|
1486
|
+
name: 'loader-invalidate',
|
|
1487
|
+
data: {
|
|
1488
|
+
scope: 'all'
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
};
|
|
1492
|
+
const unlisten = deltaBundler.listen(graph, onChange);
|
|
1493
|
+
this.loaderGraphListeners.set(graphId, unlisten);
|
|
1494
|
+
}
|
|
1495
|
+
shouldBroadcastLoaderInvalidation(changeId) {
|
|
1496
|
+
if (!changeId) {
|
|
1497
|
+
return true;
|
|
1451
1498
|
}
|
|
1499
|
+
if (this.pendingLoaderInvalidationChangeIds.has(changeId)) {
|
|
1500
|
+
return false;
|
|
1501
|
+
}
|
|
1502
|
+
this.pendingLoaderInvalidationChangeIds.add(changeId);
|
|
1503
|
+
// All listeners for a single filesystem change are dispatched synchronously from one
|
|
1504
|
+
// DeltaCalculator EventEmitter.emit(), so dedupe collisions resolve within microseconds.
|
|
1505
|
+
// The timeout exists only to bound memory: without it, this Set would accumulate one entry
|
|
1506
|
+
// per change for the lifetime of the dev server.
|
|
1507
|
+
setTimeout(()=>{
|
|
1508
|
+
this.pendingLoaderInvalidationChangeIds.delete(changeId);
|
|
1509
|
+
}, 500);
|
|
1510
|
+
return true;
|
|
1452
1511
|
}
|
|
1453
1512
|
// Direct Metro access
|
|
1454
1513
|
// Emulates the Metro dev server .bundle endpoint without having to go through a server.
|
|
@@ -1495,13 +1554,14 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1495
1554
|
type: 'bundle_build_started'
|
|
1496
1555
|
});
|
|
1497
1556
|
try {
|
|
1557
|
+
var _transformOptions_customTransformOptions;
|
|
1498
1558
|
let delta;
|
|
1499
1559
|
let revision;
|
|
1500
1560
|
try {
|
|
1501
|
-
var
|
|
1561
|
+
var _transformOptions_customTransformOptions1;
|
|
1502
1562
|
// TODO: Some bug in Metro/RSC causes this to break when changing imports in server components.
|
|
1503
1563
|
// We should resolve the bug because it results in ~6x faster bundling to reuse the graph revision.
|
|
1504
|
-
if (((
|
|
1564
|
+
if (((_transformOptions_customTransformOptions1 = transformOptions.customTransformOptions) == null ? void 0 : _transformOptions_customTransformOptions1.environment) === 'react-server') {
|
|
1505
1565
|
const props = await this.metro.getBundler().initializeGraph(// NOTE: Using absolute path instead of relative input path is a breaking change.
|
|
1506
1566
|
// entryFile,
|
|
1507
1567
|
resolvedEntryFilePath, transformOptions, resolverOptions, {
|
|
@@ -1527,6 +1587,9 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1527
1587
|
(0, _metroErrorInterface.dropStackIfContainsCodeFrame)(error);
|
|
1528
1588
|
throw error;
|
|
1529
1589
|
}
|
|
1590
|
+
if (!this.instanceMetroOptions.isExporting && transformOptions.dev !== false && ((_transformOptions_customTransformOptions = transformOptions.customTransformOptions) == null ? void 0 : _transformOptions_customTransformOptions.isLoaderBundle) === 'true') {
|
|
1591
|
+
this.setupLoaderGraphListener(revision.graphId, resolvedEntryFilePath, revision.graph);
|
|
1592
|
+
}
|
|
1530
1593
|
bundlePerfLogger == null ? void 0 : bundlePerfLogger.annotate({
|
|
1531
1594
|
int: {
|
|
1532
1595
|
graph_node_count: revision.graph.dependencies.size
|
|
@@ -1658,7 +1721,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1658
1721
|
});
|
|
1659
1722
|
}
|
|
1660
1723
|
constructor(...args){
|
|
1661
|
-
super(...args), this.metro = null, this.hmrServer = null, this.ssrHmrClients = new Map(), // Set when the server is started.
|
|
1724
|
+
super(...args), this.metro = null, this.hmrServer = null, this.ssrHmrClients = new Map(), this.loaderGraphListeners = new Map(), this.pendingLoaderInvalidationChangeIds = new Set(), // Set when the server is started.
|
|
1662
1725
|
this.instanceMetroOptions = {}, this.ssrLoadModule = async (filePath, specificOptions = {}, extras = {})=>{
|
|
1663
1726
|
// NOTE(@kitten): We don't properly initialize the server-side modules
|
|
1664
1727
|
// Instead, we first load an entrypoint with an empty bundle to initialize the runtime instead
|
|
@@ -1678,7 +1741,7 @@ class MetroBundlerDevServer extends _BundlerDevServer.BundlerDevServer {
|
|
|
1678
1741
|
}
|
|
1679
1742
|
return (0, _getStaticRenderFunctions.evalMetroAndWrapFunctions)(this.projectRoot, res.src, res.filename, res.map, specificOptions.isExporting ?? this.instanceMetroOptions.isExporting);
|
|
1680
1743
|
}, this.rscRenderer = null, this.onReloadRscEvent = null, // API Routes
|
|
1681
|
-
this.pendingRouteOperations = new Map()
|
|
1744
|
+
this.pendingRouteOperations = new Map();
|
|
1682
1745
|
}
|
|
1683
1746
|
}
|
|
1684
1747
|
function getBuildID(buildNumber) {
|