@sanity/cli 6.1.7 → 6.1.8
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/README.md +78 -78
- package/dist/actions/build/buildStudio.js +1 -1
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/services/mcp.js +32 -44
- package/dist/services/mcp.js.map +1 -1
- package/oclif.manifest.json +155 -155
- package/package.json +20 -20
|
@@ -39,7 +39,7 @@ import { shouldAutoUpdate } from './shouldAutoUpdate.js';
|
|
|
39
39
|
output,
|
|
40
40
|
workDir
|
|
41
41
|
});
|
|
42
|
-
let autoUpdatesEnabled = shouldAutoUpdate({
|
|
42
|
+
let autoUpdatesEnabled = options.calledFromDeploy ? options.autoUpdatesEnabled : shouldAutoUpdate({
|
|
43
43
|
cliConfig,
|
|
44
44
|
flags,
|
|
45
45
|
output
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/buildStudio.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {getCliTelemetry, getTimer, isInteractive} from '@sanity/cli-core'\nimport {confirm, logSymbols, select, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport semver from 'semver'\n\nimport {StudioBuildTrace} from '../../telemetry/build.telemetry.js'\nimport {getAppId} from '../../util/appId.js'\nimport {compareDependencyVersions} from '../../util/compareDependencyVersions.js'\nimport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\nimport {getPackageManagerChoice} from '../../util/packageManager/packageManagerChoice.js'\nimport {upgradePackages} from '../../util/packageManager/upgradePackages.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {buildDebug} from './buildDebug.js'\nimport {buildStaticFiles} from './buildStaticFiles.js'\nimport {buildVendorDependencies} from './buildVendorDependencies.js'\nimport {checkRequiredDependencies} from './checkRequiredDependencies.js'\nimport {checkStudioDependencyVersions} from './checkStudioDependencyVersions.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {getAutoUpdatesImportMap} from './getAutoUpdatesImportMap.js'\nimport {getStudioEnvVars} from './getStudioEnvVars.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {shouldAutoUpdate} from './shouldAutoUpdate.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const timer = getTimer()\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const unattendedMode = Boolean(flags.yes)\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n await checkStudioDependencyVersions(workDir, output)\n\n // If the check resulted in a dependency install, the CLI command will be re-run,\n // thus we want to exit early\n const {installedSanityVersion} = await checkRequiredDependencies({\n cliConfig,\n output,\n workDir,\n })\n\n let autoUpdatesEnabled = shouldAutoUpdate({cliConfig, flags, output})\n\n let autoUpdatesImports = {}\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSanityVersion = semver.parse(installedSanityVersion)?.version\n if (!cleanSanityVersion) {\n throw new Error(`Failed to parse installed Sanity version: ${installedSanityVersion}`)\n }\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n const projectId = cliConfig?.api?.projectId\n const appId = getAppId(cliConfig)\n\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !options.calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId})\n }\n\n const sanityDependencies = [\n {name: 'sanity', version: cleanSanityVersion},\n {name: '@sanity/vision', version: cleanSanityVersion},\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {appId})\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} = await compareDependencyVersions(\n sanityDependencies,\n workDir,\n {appId},\n )\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesEnabled = false\n }\n\n if (mismatched.length > 0 && autoUpdatesEnabled) {\n const versionMismatchWarning =\n `The following local package versions are different from the versions currently served at runtime.\\n` +\n `When using auto updates, we recommend that you test locally with the same versions before deploying. \\n\\n` +\n `${mismatched.map((mod) => ` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\\n')}`\n\n // If it is non-interactive or in unattended mode, we don't want to prompt\n if (isInteractive() && !unattendedMode) {\n const choice = await select({\n choices: [\n {\n name: `Upgrade local versions (recommended). You will need to run the build command again`,\n value: 'upgrade',\n },\n {\n name: `Upgrade and proceed with build`,\n value: 'upgrade-and-proceed',\n },\n {\n name: `Continue anyway`,\n value: 'continue',\n },\n {name: 'Cancel', value: 'cancel'},\n ],\n default: 'upgrade',\n message: styleText(\n 'yellow',\n `${logSymbols.warning} ${versionMismatchWarning}\\n\\nDo you want to upgrade local versions before deploying?`,\n ),\n })\n\n if (choice === 'cancel') {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n\n if (choice === 'upgrade' || choice === 'upgrade-and-proceed') {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: mismatched.map((res) => [res.pkg, res.remote]),\n },\n {output, workDir},\n )\n\n if (choice === 'upgrade') {\n return\n }\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = getStudioEnvVars()\n if (envVarKeys.length > 0) {\n output.log('\\nIncluding the following environment variables as part of the JavaScript bundle:')\n for (const key of envVarKeys) {\n output.log(`- ${key}`)\n }\n output.log('')\n }\n\n let shouldClean = true\n if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {\n shouldClean = await confirm({\n default: true,\n message: `Do you want to delete the existing directory (${outputDir}) first?`,\n })\n }\n\n // Determine base path for built studio\n const basePath = determineBasePath(cliConfig, 'studio', output)\n\n let spin: SpinnerInstance\n if (shouldClean) {\n timer.start('cleanOutputFolder')\n spin = spinner('Clean output folder').start()\n await rm(outputDir, {force: true, recursive: true})\n const cleanDuration = timer.end('cleanOutputFolder')\n spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`\n spin.succeed()\n }\n\n spin = spinner(`Build Sanity Studio`).start()\n\n const trace = getCliTelemetry().trace(StudioBuildTrace)\n trace.start()\n\n let importMap\n\n if (autoUpdatesEnabled) {\n importMap = {\n imports: {\n ...(await buildVendorDependencies({basePath, cwd: workDir, isApp: false, outputDir})),\n ...autoUpdatesImports,\n },\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n basePath,\n cwd: workDir,\n importMap,\n minify: Boolean(flags.minify),\n outputDir,\n reactCompiler:\n cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n sourceMap: Boolean(flags['source-maps']),\n vite: cliConfig && 'vite' in cliConfig ? cliConfig.vite : undefined,\n })\n\n trace.log({\n outputSize: bundle.chunks\n .flatMap((chunk) => chunk.modules.flatMap((mod) => mod.renderedLength))\n .reduce((sum, n) => sum + n, 0),\n })\n const buildDuration = timer.end('bundleStudio')\n\n spin.text = `Build Sanity Studio (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n trace.complete()\n if (flags.stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n } catch (error) {\n spin.fail()\n trace.error(error)\n const message = error instanceof Error ? error.message : String(error)\n buildDebug(`Failed to build Sanity Studio`, {error})\n output.error(`Failed to build Sanity Studio: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","getCliTelemetry","getTimer","isInteractive","confirm","logSymbols","select","spinner","semver","StudioBuildTrace","getAppId","compareDependencyVersions","formatModuleSizes","sortModulesBySize","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","buildDebug","buildStaticFiles","buildVendorDependencies","checkRequiredDependencies","checkStudioDependencyVersions","determineBasePath","getAutoUpdatesImportMap","getStudioEnvVars","handlePrereleaseVersions","shouldAutoUpdate","buildStudio","options","timer","cliConfig","flags","outDir","output","workDir","unattendedMode","Boolean","yes","defaultOutputDir","resolve","join","outputDir","installedSanityVersion","autoUpdatesEnabled","autoUpdatesImports","cleanSanityVersion","parse","version","Error","log","info","projectId","api","appId","calledFromDeploy","appType","sanityDependencies","name","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","choice","choices","value","default","message","warning","error","exit","packageManager","interactive","chosen","packages","res","warn","envVarKeys","key","shouldClean","basePath","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","importMap","imports","cwd","isApp","bundle","minify","reactCompiler","undefined","sourceMap","vite","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","complete","stats","slice","fail","String"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/buildStudio.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {getCliTelemetry, getTimer, isInteractive} from '@sanity/cli-core'\nimport {confirm, logSymbols, select, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport semver from 'semver'\n\nimport {StudioBuildTrace} from '../../telemetry/build.telemetry.js'\nimport {getAppId} from '../../util/appId.js'\nimport {compareDependencyVersions} from '../../util/compareDependencyVersions.js'\nimport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\nimport {getPackageManagerChoice} from '../../util/packageManager/packageManagerChoice.js'\nimport {upgradePackages} from '../../util/packageManager/upgradePackages.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {buildDebug} from './buildDebug.js'\nimport {buildStaticFiles} from './buildStaticFiles.js'\nimport {buildVendorDependencies} from './buildVendorDependencies.js'\nimport {checkRequiredDependencies} from './checkRequiredDependencies.js'\nimport {checkStudioDependencyVersions} from './checkStudioDependencyVersions.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {getAutoUpdatesImportMap} from './getAutoUpdatesImportMap.js'\nimport {getStudioEnvVars} from './getStudioEnvVars.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {shouldAutoUpdate} from './shouldAutoUpdate.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const timer = getTimer()\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const unattendedMode = Boolean(flags.yes)\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n await checkStudioDependencyVersions(workDir, output)\n\n // If the check resulted in a dependency install, the CLI command will be re-run,\n // thus we want to exit early\n const {installedSanityVersion} = await checkRequiredDependencies({\n cliConfig,\n output,\n workDir,\n })\n\n let autoUpdatesEnabled = options.calledFromDeploy\n ? options.autoUpdatesEnabled\n : shouldAutoUpdate({cliConfig, flags, output})\n\n let autoUpdatesImports = {}\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSanityVersion = semver.parse(installedSanityVersion)?.version\n if (!cleanSanityVersion) {\n throw new Error(`Failed to parse installed Sanity version: ${installedSanityVersion}`)\n }\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n const projectId = cliConfig?.api?.projectId\n const appId = getAppId(cliConfig)\n\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !options.calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId})\n }\n\n const sanityDependencies = [\n {name: 'sanity', version: cleanSanityVersion},\n {name: '@sanity/vision', version: cleanSanityVersion},\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {appId})\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} = await compareDependencyVersions(\n sanityDependencies,\n workDir,\n {appId},\n )\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesEnabled = false\n }\n\n if (mismatched.length > 0 && autoUpdatesEnabled) {\n const versionMismatchWarning =\n `The following local package versions are different from the versions currently served at runtime.\\n` +\n `When using auto updates, we recommend that you test locally with the same versions before deploying. \\n\\n` +\n `${mismatched.map((mod) => ` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\\n')}`\n\n // If it is non-interactive or in unattended mode, we don't want to prompt\n if (isInteractive() && !unattendedMode) {\n const choice = await select({\n choices: [\n {\n name: `Upgrade local versions (recommended). You will need to run the build command again`,\n value: 'upgrade',\n },\n {\n name: `Upgrade and proceed with build`,\n value: 'upgrade-and-proceed',\n },\n {\n name: `Continue anyway`,\n value: 'continue',\n },\n {name: 'Cancel', value: 'cancel'},\n ],\n default: 'upgrade',\n message: styleText(\n 'yellow',\n `${logSymbols.warning} ${versionMismatchWarning}\\n\\nDo you want to upgrade local versions before deploying?`,\n ),\n })\n\n if (choice === 'cancel') {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n\n if (choice === 'upgrade' || choice === 'upgrade-and-proceed') {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: mismatched.map((res) => [res.pkg, res.remote]),\n },\n {output, workDir},\n )\n\n if (choice === 'upgrade') {\n return\n }\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = getStudioEnvVars()\n if (envVarKeys.length > 0) {\n output.log('\\nIncluding the following environment variables as part of the JavaScript bundle:')\n for (const key of envVarKeys) {\n output.log(`- ${key}`)\n }\n output.log('')\n }\n\n let shouldClean = true\n if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {\n shouldClean = await confirm({\n default: true,\n message: `Do you want to delete the existing directory (${outputDir}) first?`,\n })\n }\n\n // Determine base path for built studio\n const basePath = determineBasePath(cliConfig, 'studio', output)\n\n let spin: SpinnerInstance\n if (shouldClean) {\n timer.start('cleanOutputFolder')\n spin = spinner('Clean output folder').start()\n await rm(outputDir, {force: true, recursive: true})\n const cleanDuration = timer.end('cleanOutputFolder')\n spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`\n spin.succeed()\n }\n\n spin = spinner(`Build Sanity Studio`).start()\n\n const trace = getCliTelemetry().trace(StudioBuildTrace)\n trace.start()\n\n let importMap\n\n if (autoUpdatesEnabled) {\n importMap = {\n imports: {\n ...(await buildVendorDependencies({basePath, cwd: workDir, isApp: false, outputDir})),\n ...autoUpdatesImports,\n },\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n basePath,\n cwd: workDir,\n importMap,\n minify: Boolean(flags.minify),\n outputDir,\n reactCompiler:\n cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n sourceMap: Boolean(flags['source-maps']),\n vite: cliConfig && 'vite' in cliConfig ? cliConfig.vite : undefined,\n })\n\n trace.log({\n outputSize: bundle.chunks\n .flatMap((chunk) => chunk.modules.flatMap((mod) => mod.renderedLength))\n .reduce((sum, n) => sum + n, 0),\n })\n const buildDuration = timer.end('bundleStudio')\n\n spin.text = `Build Sanity Studio (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n trace.complete()\n if (flags.stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n } catch (error) {\n spin.fail()\n trace.error(error)\n const message = error instanceof Error ? error.message : String(error)\n buildDebug(`Failed to build Sanity Studio`, {error})\n output.error(`Failed to build Sanity Studio: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","getCliTelemetry","getTimer","isInteractive","confirm","logSymbols","select","spinner","semver","StudioBuildTrace","getAppId","compareDependencyVersions","formatModuleSizes","sortModulesBySize","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","buildDebug","buildStaticFiles","buildVendorDependencies","checkRequiredDependencies","checkStudioDependencyVersions","determineBasePath","getAutoUpdatesImportMap","getStudioEnvVars","handlePrereleaseVersions","shouldAutoUpdate","buildStudio","options","timer","cliConfig","flags","outDir","output","workDir","unattendedMode","Boolean","yes","defaultOutputDir","resolve","join","outputDir","installedSanityVersion","autoUpdatesEnabled","calledFromDeploy","autoUpdatesImports","cleanSanityVersion","parse","version","Error","log","info","projectId","api","appId","appType","sanityDependencies","name","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","choice","choices","value","default","message","warning","error","exit","packageManager","interactive","chosen","packages","res","warn","envVarKeys","key","shouldClean","basePath","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","importMap","imports","cwd","isApp","bundle","minify","reactCompiler","undefined","sourceMap","vite","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","complete","stats","slice","fail","String"],"mappings":"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"}
|
package/dist/services/mcp.js
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import { getGlobalCliClient, subdebug } from '@sanity/cli-core';
|
|
2
|
-
import {
|
|
2
|
+
import { isHttpError } from '@sanity/client';
|
|
3
3
|
export const MCP_API_VERSION = '2025-12-09';
|
|
4
4
|
export const MCP_SERVER_URL = 'https://mcp.sanity.io';
|
|
5
5
|
export const MCP_JOURNEY_API_VERSION = 'v2024-02-23';
|
|
6
6
|
const debug = subdebug('mcp:service');
|
|
7
|
-
let mcpRequester;
|
|
8
|
-
function getMCPRequester() {
|
|
9
|
-
if (!mcpRequester) {
|
|
10
|
-
mcpRequester = createRequester({
|
|
11
|
-
middleware: {
|
|
12
|
-
httpErrors: false,
|
|
13
|
-
promise: {
|
|
14
|
-
onlyBody: false
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return mcpRequester;
|
|
20
|
-
}
|
|
21
7
|
/**
|
|
22
8
|
* Create a child token for MCP usage
|
|
23
9
|
* This token is tied to the parent CLI token and will be invalidated
|
|
@@ -48,42 +34,44 @@ function getMCPRequester() {
|
|
|
48
34
|
return tokenResponse.token;
|
|
49
35
|
}
|
|
50
36
|
/**
|
|
51
|
-
* Validate an MCP token against the
|
|
37
|
+
* Validate an MCP token by checking it against the Sanity API.
|
|
52
38
|
*
|
|
53
|
-
* MCP tokens are
|
|
54
|
-
* api.sanity.io
|
|
39
|
+
* MCP tokens are standard Sanity session tokens (`sk…`), so we validate
|
|
40
|
+
* by calling `/users/me` on `api.sanity.io`. A 200 means the token is
|
|
41
|
+
* alive; a 401/403 means it is dead and the caller should prompt for
|
|
42
|
+
* re-configuration.
|
|
55
43
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
44
|
+
* Transient errors (5xx, network failures, timeouts) are rethrown so the
|
|
45
|
+
* caller can decide how to handle them — typically by assuming the token
|
|
46
|
+
* is still valid rather than falsely marking it as expired.
|
|
47
|
+
*
|
|
48
|
+
* We intentionally do NOT probe `mcp.sanity.io` because the MCP server
|
|
49
|
+
* lets invalid bearer tokens through for protocol-compatibility reasons,
|
|
50
|
+
* which causes the CLI to falsely treat dead tokens as valid.
|
|
60
51
|
*
|
|
61
52
|
* @internal
|
|
62
53
|
*/ export async function validateMCPToken(token) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// than falsely marking it as expired (see below).
|
|
68
|
-
const res = await request({
|
|
69
|
-
body: '{}',
|
|
70
|
-
headers: {
|
|
71
|
-
Authorization: `Bearer ${token}`,
|
|
72
|
-
'Content-Type': 'application/json'
|
|
73
|
-
},
|
|
74
|
-
method: 'POST',
|
|
75
|
-
timeout: 2500,
|
|
76
|
-
url: MCP_SERVER_URL
|
|
54
|
+
const client = await getGlobalCliClient({
|
|
55
|
+
apiVersion: MCP_API_VERSION,
|
|
56
|
+
requireUser: false,
|
|
57
|
+
token
|
|
77
58
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
59
|
+
try {
|
|
60
|
+
await client.request({
|
|
61
|
+
timeout: 2500,
|
|
62
|
+
uri: '/users/me'
|
|
63
|
+
});
|
|
64
|
+
return true;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
// 401/403 definitively mean "dead token"
|
|
67
|
+
if (isHttpError(err) && (err.statusCode === 401 || err.statusCode === 403)) {
|
|
68
|
+
debug('MCP token validation failed with %d', err.statusCode);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Everything else (5xx, network errors, timeouts) is rethrown so the
|
|
72
|
+
// caller can decide — typically assumes valid rather than forcing re-auth.
|
|
73
|
+
throw err;
|
|
85
74
|
}
|
|
86
|
-
return true;
|
|
87
75
|
}
|
|
88
76
|
/**
|
|
89
77
|
* Fetches the post-init MCP prompt from the Journey API and interpolates editor names.
|
package/dist/services/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/services/mcp.ts"],"sourcesContent":["import {getGlobalCliClient, subdebug} from '@sanity/cli-core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/services/mcp.ts"],"sourcesContent":["import {getGlobalCliClient, subdebug} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nexport const MCP_API_VERSION = '2025-12-09'\nexport const MCP_SERVER_URL = 'https://mcp.sanity.io'\nexport const MCP_JOURNEY_API_VERSION = 'v2024-02-23'\n\nconst debug = subdebug('mcp:service')\n\ninterface PostInitPromptResponse {\n message?: string\n}\n\n/**\n * Create a child token for MCP usage\n * This token is tied to the parent CLI token and will be invalidated\n * when the parent token is invalidated (e.g., on logout)\n *\n * @returns The MCP token string\n * @internal\n */\nexport async function createMCPToken(): Promise<string> {\n const client = await getGlobalCliClient({\n apiVersion: MCP_API_VERSION,\n requireUser: true,\n })\n\n const sessionResponse = await client.request<{id: string; sid: string}>({\n body: {\n sourceId: 'sanity-mcp',\n withStamp: false,\n },\n method: 'POST',\n uri: '/auth/session/create',\n })\n\n const tokenResponse = await client.request<{label: string; token: string}>({\n method: 'GET',\n query: {sid: sessionResponse.sid},\n uri: '/auth/fetch',\n })\n\n return tokenResponse.token\n}\n\n/**\n * Validate an MCP token by checking it against the Sanity API.\n *\n * MCP tokens are standard Sanity session tokens (`sk…`), so we validate\n * by calling `/users/me` on `api.sanity.io`. A 200 means the token is\n * alive; a 401/403 means it is dead and the caller should prompt for\n * re-configuration.\n *\n * Transient errors (5xx, network failures, timeouts) are rethrown so the\n * caller can decide how to handle them — typically by assuming the token\n * is still valid rather than falsely marking it as expired.\n *\n * We intentionally do NOT probe `mcp.sanity.io` because the MCP server\n * lets invalid bearer tokens through for protocol-compatibility reasons,\n * which causes the CLI to falsely treat dead tokens as valid.\n *\n * @internal\n */\nexport async function validateMCPToken(token: string): Promise<boolean> {\n const client = await getGlobalCliClient({\n apiVersion: MCP_API_VERSION,\n requireUser: false,\n token,\n })\n\n try {\n await client.request({timeout: 2500, uri: '/users/me'})\n return true\n } catch (err) {\n // 401/403 definitively mean \"dead token\"\n if (isHttpError(err) && (err.statusCode === 401 || err.statusCode === 403)) {\n debug('MCP token validation failed with %d', err.statusCode)\n return false\n }\n\n // Everything else (5xx, network errors, timeouts) is rethrown so the\n // caller can decide — typically assumes valid rather than forcing re-auth.\n throw err\n }\n}\n\n/**\n * Fetches the post-init MCP prompt from the Journey API and interpolates editor names.\n * Falls back to a hardcoded default if the API call fails, times out, or returns empty.\n * Text wrapped in **markers** will be formatted with cyan color.\n */\nexport async function getPostInitPrompt() {\n const client = await getGlobalCliClient({apiVersion: MCP_JOURNEY_API_VERSION, requireUser: false})\n return await client.request<PostInitPromptResponse | null>({\n method: 'GET',\n timeout: 1000,\n uri: '/journey/mcp/post-init-prompt',\n })\n}\n"],"names":["getGlobalCliClient","subdebug","isHttpError","MCP_API_VERSION","MCP_SERVER_URL","MCP_JOURNEY_API_VERSION","debug","createMCPToken","client","apiVersion","requireUser","sessionResponse","request","body","sourceId","withStamp","method","uri","tokenResponse","query","sid","token","validateMCPToken","timeout","err","statusCode","getPostInitPrompt"],"mappings":"AAAA,SAAQA,kBAAkB,EAAEC,QAAQ,QAAO,mBAAkB;AAC7D,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,OAAO,MAAMC,kBAAkB,aAAY;AAC3C,OAAO,MAAMC,iBAAiB,wBAAuB;AACrD,OAAO,MAAMC,0BAA0B,cAAa;AAEpD,MAAMC,QAAQL,SAAS;AAMvB;;;;;;;CAOC,GACD,OAAO,eAAeM;IACpB,MAAMC,SAAS,MAAMR,mBAAmB;QACtCS,YAAYN;QACZO,aAAa;IACf;IAEA,MAAMC,kBAAkB,MAAMH,OAAOI,OAAO,CAA4B;QACtEC,MAAM;YACJC,UAAU;YACVC,WAAW;QACb;QACAC,QAAQ;QACRC,KAAK;IACP;IAEA,MAAMC,gBAAgB,MAAMV,OAAOI,OAAO,CAAiC;QACzEI,QAAQ;QACRG,OAAO;YAACC,KAAKT,gBAAgBS,GAAG;QAAA;QAChCH,KAAK;IACP;IAEA,OAAOC,cAAcG,KAAK;AAC5B;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,eAAeC,iBAAiBD,KAAa;IAClD,MAAMb,SAAS,MAAMR,mBAAmB;QACtCS,YAAYN;QACZO,aAAa;QACbW;IACF;IAEA,IAAI;QACF,MAAMb,OAAOI,OAAO,CAAC;YAACW,SAAS;YAAMN,KAAK;QAAW;QACrD,OAAO;IACT,EAAE,OAAOO,KAAK;QACZ,yCAAyC;QACzC,IAAItB,YAAYsB,QAASA,CAAAA,IAAIC,UAAU,KAAK,OAAOD,IAAIC,UAAU,KAAK,GAAE,GAAI;YAC1EnB,MAAM,uCAAuCkB,IAAIC,UAAU;YAC3D,OAAO;QACT;QAEA,qEAAqE;QACrE,2EAA2E;QAC3E,MAAMD;IACR;AACF;AAEA;;;;CAIC,GACD,OAAO,eAAeE;IACpB,MAAMlB,SAAS,MAAMR,mBAAmB;QAACS,YAAYJ;QAAyBK,aAAa;IAAK;IAChG,OAAO,MAAMF,OAAOI,OAAO,CAAgC;QACzDI,QAAQ;QACRO,SAAS;QACTN,KAAK;IACP;AACF"}
|
package/oclif.manifest.json
CHANGED
|
@@ -953,6 +953,160 @@
|
|
|
953
953
|
"versions.js"
|
|
954
954
|
]
|
|
955
955
|
},
|
|
956
|
+
"cors:add": {
|
|
957
|
+
"aliases": [],
|
|
958
|
+
"args": {
|
|
959
|
+
"origin": {
|
|
960
|
+
"description": "Origin to allow (e.g., https://example.com)",
|
|
961
|
+
"name": "origin",
|
|
962
|
+
"required": true
|
|
963
|
+
}
|
|
964
|
+
},
|
|
965
|
+
"description": "Allow a new origin to use your project API through CORS",
|
|
966
|
+
"examples": [
|
|
967
|
+
{
|
|
968
|
+
"command": "<%= config.bin %> <%= command.id %>",
|
|
969
|
+
"description": "Interactively add a CORS origin"
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
"command": "<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials",
|
|
973
|
+
"description": "Add a localhost origin without credentials"
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"command": "<%= config.bin %> <%= command.id %> https://myapp.com --credentials",
|
|
977
|
+
"description": "Add a production origin with credentials allowed"
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
"command": "<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123",
|
|
981
|
+
"description": "Add a CORS origin for a specific project"
|
|
982
|
+
}
|
|
983
|
+
],
|
|
984
|
+
"flags": {
|
|
985
|
+
"project-id": {
|
|
986
|
+
"char": "p",
|
|
987
|
+
"description": "Project ID to add CORS origin to (overrides CLI configuration)",
|
|
988
|
+
"helpGroup": "OVERRIDE",
|
|
989
|
+
"name": "project-id",
|
|
990
|
+
"hasDynamicHelp": false,
|
|
991
|
+
"helpValue": "<id>",
|
|
992
|
+
"multiple": false,
|
|
993
|
+
"type": "option"
|
|
994
|
+
},
|
|
995
|
+
"credentials": {
|
|
996
|
+
"description": "Allow credentials (token/cookie) to be sent from this origin",
|
|
997
|
+
"name": "credentials",
|
|
998
|
+
"required": false,
|
|
999
|
+
"allowNo": true,
|
|
1000
|
+
"type": "boolean"
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
"hasDynamicHelp": false,
|
|
1004
|
+
"hiddenAliases": [],
|
|
1005
|
+
"id": "cors:add",
|
|
1006
|
+
"pluginAlias": "@sanity/cli",
|
|
1007
|
+
"pluginName": "@sanity/cli",
|
|
1008
|
+
"pluginType": "core",
|
|
1009
|
+
"strict": true,
|
|
1010
|
+
"isESM": true,
|
|
1011
|
+
"relativePath": [
|
|
1012
|
+
"dist",
|
|
1013
|
+
"commands",
|
|
1014
|
+
"cors",
|
|
1015
|
+
"add.js"
|
|
1016
|
+
]
|
|
1017
|
+
},
|
|
1018
|
+
"cors:delete": {
|
|
1019
|
+
"aliases": [],
|
|
1020
|
+
"args": {
|
|
1021
|
+
"origin": {
|
|
1022
|
+
"description": "Origin to delete (will prompt if not provided)",
|
|
1023
|
+
"name": "origin",
|
|
1024
|
+
"required": false
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
"description": "Delete an existing CORS origin from your project",
|
|
1028
|
+
"examples": [
|
|
1029
|
+
{
|
|
1030
|
+
"command": "<%= config.bin %> <%= command.id %>",
|
|
1031
|
+
"description": "Interactively select and delete a CORS origin"
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
"command": "<%= config.bin %> <%= command.id %> https://example.com",
|
|
1035
|
+
"description": "Delete a specific CORS origin"
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
"command": "<%= config.bin %> <%= command.id %> --project-id abc123",
|
|
1039
|
+
"description": "Delete a CORS origin from a specific project"
|
|
1040
|
+
}
|
|
1041
|
+
],
|
|
1042
|
+
"flags": {
|
|
1043
|
+
"project-id": {
|
|
1044
|
+
"char": "p",
|
|
1045
|
+
"description": "Project ID to delete CORS origin from (overrides CLI configuration)",
|
|
1046
|
+
"helpGroup": "OVERRIDE",
|
|
1047
|
+
"name": "project-id",
|
|
1048
|
+
"hasDynamicHelp": false,
|
|
1049
|
+
"helpValue": "<id>",
|
|
1050
|
+
"multiple": false,
|
|
1051
|
+
"type": "option"
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
"hasDynamicHelp": false,
|
|
1055
|
+
"hiddenAliases": [],
|
|
1056
|
+
"id": "cors:delete",
|
|
1057
|
+
"pluginAlias": "@sanity/cli",
|
|
1058
|
+
"pluginName": "@sanity/cli",
|
|
1059
|
+
"pluginType": "core",
|
|
1060
|
+
"strict": true,
|
|
1061
|
+
"isESM": true,
|
|
1062
|
+
"relativePath": [
|
|
1063
|
+
"dist",
|
|
1064
|
+
"commands",
|
|
1065
|
+
"cors",
|
|
1066
|
+
"delete.js"
|
|
1067
|
+
]
|
|
1068
|
+
},
|
|
1069
|
+
"cors:list": {
|
|
1070
|
+
"aliases": [],
|
|
1071
|
+
"args": {},
|
|
1072
|
+
"description": "List all origins allowed to access the API for this project",
|
|
1073
|
+
"examples": [
|
|
1074
|
+
{
|
|
1075
|
+
"command": "<%= config.bin %> <%= command.id %>",
|
|
1076
|
+
"description": "List CORS origins for the current project"
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
"command": "<%= config.bin %> <%= command.id %> --project-id abc123",
|
|
1080
|
+
"description": "List CORS origins for a specific project"
|
|
1081
|
+
}
|
|
1082
|
+
],
|
|
1083
|
+
"flags": {
|
|
1084
|
+
"project-id": {
|
|
1085
|
+
"char": "p",
|
|
1086
|
+
"description": "Project ID to list CORS origins for (overrides CLI configuration)",
|
|
1087
|
+
"helpGroup": "OVERRIDE",
|
|
1088
|
+
"name": "project-id",
|
|
1089
|
+
"hasDynamicHelp": false,
|
|
1090
|
+
"helpValue": "<id>",
|
|
1091
|
+
"multiple": false,
|
|
1092
|
+
"type": "option"
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
"hasDynamicHelp": false,
|
|
1096
|
+
"hiddenAliases": [],
|
|
1097
|
+
"id": "cors:list",
|
|
1098
|
+
"pluginAlias": "@sanity/cli",
|
|
1099
|
+
"pluginName": "@sanity/cli",
|
|
1100
|
+
"pluginType": "core",
|
|
1101
|
+
"strict": true,
|
|
1102
|
+
"isESM": true,
|
|
1103
|
+
"relativePath": [
|
|
1104
|
+
"dist",
|
|
1105
|
+
"commands",
|
|
1106
|
+
"cors",
|
|
1107
|
+
"list.js"
|
|
1108
|
+
]
|
|
1109
|
+
},
|
|
956
1110
|
"backup:disable": {
|
|
957
1111
|
"aliases": [],
|
|
958
1112
|
"args": {
|
|
@@ -1208,160 +1362,6 @@
|
|
|
1208
1362
|
"list.js"
|
|
1209
1363
|
]
|
|
1210
1364
|
},
|
|
1211
|
-
"cors:add": {
|
|
1212
|
-
"aliases": [],
|
|
1213
|
-
"args": {
|
|
1214
|
-
"origin": {
|
|
1215
|
-
"description": "Origin to allow (e.g., https://example.com)",
|
|
1216
|
-
"name": "origin",
|
|
1217
|
-
"required": true
|
|
1218
|
-
}
|
|
1219
|
-
},
|
|
1220
|
-
"description": "Allow a new origin to use your project API through CORS",
|
|
1221
|
-
"examples": [
|
|
1222
|
-
{
|
|
1223
|
-
"command": "<%= config.bin %> <%= command.id %>",
|
|
1224
|
-
"description": "Interactively add a CORS origin"
|
|
1225
|
-
},
|
|
1226
|
-
{
|
|
1227
|
-
"command": "<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials",
|
|
1228
|
-
"description": "Add a localhost origin without credentials"
|
|
1229
|
-
},
|
|
1230
|
-
{
|
|
1231
|
-
"command": "<%= config.bin %> <%= command.id %> https://myapp.com --credentials",
|
|
1232
|
-
"description": "Add a production origin with credentials allowed"
|
|
1233
|
-
},
|
|
1234
|
-
{
|
|
1235
|
-
"command": "<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123",
|
|
1236
|
-
"description": "Add a CORS origin for a specific project"
|
|
1237
|
-
}
|
|
1238
|
-
],
|
|
1239
|
-
"flags": {
|
|
1240
|
-
"project-id": {
|
|
1241
|
-
"char": "p",
|
|
1242
|
-
"description": "Project ID to add CORS origin to (overrides CLI configuration)",
|
|
1243
|
-
"helpGroup": "OVERRIDE",
|
|
1244
|
-
"name": "project-id",
|
|
1245
|
-
"hasDynamicHelp": false,
|
|
1246
|
-
"helpValue": "<id>",
|
|
1247
|
-
"multiple": false,
|
|
1248
|
-
"type": "option"
|
|
1249
|
-
},
|
|
1250
|
-
"credentials": {
|
|
1251
|
-
"description": "Allow credentials (token/cookie) to be sent from this origin",
|
|
1252
|
-
"name": "credentials",
|
|
1253
|
-
"required": false,
|
|
1254
|
-
"allowNo": true,
|
|
1255
|
-
"type": "boolean"
|
|
1256
|
-
}
|
|
1257
|
-
},
|
|
1258
|
-
"hasDynamicHelp": false,
|
|
1259
|
-
"hiddenAliases": [],
|
|
1260
|
-
"id": "cors:add",
|
|
1261
|
-
"pluginAlias": "@sanity/cli",
|
|
1262
|
-
"pluginName": "@sanity/cli",
|
|
1263
|
-
"pluginType": "core",
|
|
1264
|
-
"strict": true,
|
|
1265
|
-
"isESM": true,
|
|
1266
|
-
"relativePath": [
|
|
1267
|
-
"dist",
|
|
1268
|
-
"commands",
|
|
1269
|
-
"cors",
|
|
1270
|
-
"add.js"
|
|
1271
|
-
]
|
|
1272
|
-
},
|
|
1273
|
-
"cors:delete": {
|
|
1274
|
-
"aliases": [],
|
|
1275
|
-
"args": {
|
|
1276
|
-
"origin": {
|
|
1277
|
-
"description": "Origin to delete (will prompt if not provided)",
|
|
1278
|
-
"name": "origin",
|
|
1279
|
-
"required": false
|
|
1280
|
-
}
|
|
1281
|
-
},
|
|
1282
|
-
"description": "Delete an existing CORS origin from your project",
|
|
1283
|
-
"examples": [
|
|
1284
|
-
{
|
|
1285
|
-
"command": "<%= config.bin %> <%= command.id %>",
|
|
1286
|
-
"description": "Interactively select and delete a CORS origin"
|
|
1287
|
-
},
|
|
1288
|
-
{
|
|
1289
|
-
"command": "<%= config.bin %> <%= command.id %> https://example.com",
|
|
1290
|
-
"description": "Delete a specific CORS origin"
|
|
1291
|
-
},
|
|
1292
|
-
{
|
|
1293
|
-
"command": "<%= config.bin %> <%= command.id %> --project-id abc123",
|
|
1294
|
-
"description": "Delete a CORS origin from a specific project"
|
|
1295
|
-
}
|
|
1296
|
-
],
|
|
1297
|
-
"flags": {
|
|
1298
|
-
"project-id": {
|
|
1299
|
-
"char": "p",
|
|
1300
|
-
"description": "Project ID to delete CORS origin from (overrides CLI configuration)",
|
|
1301
|
-
"helpGroup": "OVERRIDE",
|
|
1302
|
-
"name": "project-id",
|
|
1303
|
-
"hasDynamicHelp": false,
|
|
1304
|
-
"helpValue": "<id>",
|
|
1305
|
-
"multiple": false,
|
|
1306
|
-
"type": "option"
|
|
1307
|
-
}
|
|
1308
|
-
},
|
|
1309
|
-
"hasDynamicHelp": false,
|
|
1310
|
-
"hiddenAliases": [],
|
|
1311
|
-
"id": "cors:delete",
|
|
1312
|
-
"pluginAlias": "@sanity/cli",
|
|
1313
|
-
"pluginName": "@sanity/cli",
|
|
1314
|
-
"pluginType": "core",
|
|
1315
|
-
"strict": true,
|
|
1316
|
-
"isESM": true,
|
|
1317
|
-
"relativePath": [
|
|
1318
|
-
"dist",
|
|
1319
|
-
"commands",
|
|
1320
|
-
"cors",
|
|
1321
|
-
"delete.js"
|
|
1322
|
-
]
|
|
1323
|
-
},
|
|
1324
|
-
"cors:list": {
|
|
1325
|
-
"aliases": [],
|
|
1326
|
-
"args": {},
|
|
1327
|
-
"description": "List all origins allowed to access the API for this project",
|
|
1328
|
-
"examples": [
|
|
1329
|
-
{
|
|
1330
|
-
"command": "<%= config.bin %> <%= command.id %>",
|
|
1331
|
-
"description": "List CORS origins for the current project"
|
|
1332
|
-
},
|
|
1333
|
-
{
|
|
1334
|
-
"command": "<%= config.bin %> <%= command.id %> --project-id abc123",
|
|
1335
|
-
"description": "List CORS origins for a specific project"
|
|
1336
|
-
}
|
|
1337
|
-
],
|
|
1338
|
-
"flags": {
|
|
1339
|
-
"project-id": {
|
|
1340
|
-
"char": "p",
|
|
1341
|
-
"description": "Project ID to list CORS origins for (overrides CLI configuration)",
|
|
1342
|
-
"helpGroup": "OVERRIDE",
|
|
1343
|
-
"name": "project-id",
|
|
1344
|
-
"hasDynamicHelp": false,
|
|
1345
|
-
"helpValue": "<id>",
|
|
1346
|
-
"multiple": false,
|
|
1347
|
-
"type": "option"
|
|
1348
|
-
}
|
|
1349
|
-
},
|
|
1350
|
-
"hasDynamicHelp": false,
|
|
1351
|
-
"hiddenAliases": [],
|
|
1352
|
-
"id": "cors:list",
|
|
1353
|
-
"pluginAlias": "@sanity/cli",
|
|
1354
|
-
"pluginName": "@sanity/cli",
|
|
1355
|
-
"pluginType": "core",
|
|
1356
|
-
"strict": true,
|
|
1357
|
-
"isESM": true,
|
|
1358
|
-
"relativePath": [
|
|
1359
|
-
"dist",
|
|
1360
|
-
"commands",
|
|
1361
|
-
"cors",
|
|
1362
|
-
"list.js"
|
|
1363
|
-
]
|
|
1364
|
-
},
|
|
1365
1365
|
"dataset:copy": {
|
|
1366
1366
|
"aliases": [],
|
|
1367
1367
|
"args": {
|
|
@@ -4943,5 +4943,5 @@
|
|
|
4943
4943
|
]
|
|
4944
4944
|
}
|
|
4945
4945
|
},
|
|
4946
|
-
"version": "6.1.
|
|
4946
|
+
"version": "6.1.8"
|
|
4947
4947
|
}
|