@sanity/cli 6.1.6 → 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.
@@ -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":"AAAA,SAAQA,EAAE,QAAO,mBAAkB;AACnC,OAAOC,UAAU,YAAW;AAC5B,SAAQC,SAAS,QAAO,YAAW;AAEnC,SAAQC,eAAe,EAAEC,QAAQ,EAAEC,aAAa,QAAO,mBAAkB;AACzE,SAAQC,OAAO,EAAEC,UAAU,EAAEC,MAAM,EAAEC,OAAO,QAA6B,sBAAqB;AAC9F,OAAOC,YAAY,SAAQ;AAE3B,SAAQC,gBAAgB,QAAO,qCAAoC;AACnE,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,yBAAyB,QAAO,0CAAyC;AACjF,SAAQC,iBAAiB,EAAEC,iBAAiB,QAAO,kCAAiC;AACpF,SAAQC,uBAAuB,QAAO,oDAAmD;AACzF,SAAQC,eAAe,QAAO,+CAA8C;AAC5E,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,UAAU,QAAO,kBAAiB;AAC1C,SAAQC,gBAAgB,QAAO,wBAAuB;AACtD,SAAQC,uBAAuB,QAAO,+BAA8B;AACpE,SAAQC,yBAAyB,QAAO,iCAAgC;AACxE,SAAQC,6BAA6B,QAAO,qCAAoC;AAChF,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,uBAAuB,QAAO,+BAA8B;AACpE,SAAQC,gBAAgB,QAAO,wBAAuB;AACtD,SAAQC,wBAAwB,QAAO,gCAA+B;AACtE,SAAQC,gBAAgB,QAAO,wBAAuB;AAGtD;;;;CAIC,GACD,OAAO,eAAeC,YAAYC,OAAqB;IACrD,MAAMC,QAAQ3B;IACd,MAAM,EAAC4B,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGN;IAEpD,MAAMO,iBAAiBC,QAAQL,MAAMM,GAAG;IACxC,MAAMC,mBAAmBvC,KAAKwC,OAAO,CAACxC,KAAKyC,IAAI,CAACN,SAAS;IACzD,MAAMO,YAAY1C,KAAKwC,OAAO,CAACP,UAAUM;IAEzC,MAAMjB,8BAA8Ba,SAASD;IAE7C,iFAAiF;IACjF,6BAA6B;IAC7B,MAAM,EAACS,sBAAsB,EAAC,GAAG,MAAMtB,0BAA0B;QAC/DU;QACAG;QACAC;IACF;IAEA,IAAIS,qBAAqBf,QAAQgB,gBAAgB,GAC7ChB,QAAQe,kBAAkB,GAC1BjB,iBAAiB;QAACI;QAAWC;QAAOE;IAAM;IAE9C,IAAIY,qBAAqB,CAAC;IAE1B,IAAIF,oBAAoB;QACtB,iFAAiF;QACjF,MAAMG,qBAAqBtC,OAAOuC,KAAK,CAACL,yBAAyBM;QACjE,IAAI,CAACF,oBAAoB;YACvB,MAAM,IAAIG,MAAM,CAAC,0CAA0C,EAAEP,wBAAwB;QACvF;QAEAT,OAAOiB,GAAG,CAAC,GAAG7C,WAAW8C,IAAI,CAAC,mCAAmC,CAAC;QAElE,MAAMC,YAAYtB,WAAWuB,KAAKD;QAClC,MAAME,QAAQ5C,SAASoB;QAEvB,wDAAwD;QACxD,kEAAkE;QAClE,yDAAyD;QACzD,IAAI,CAACwB,SAAS,CAAC1B,QAAQgB,gBAAgB,EAAE;YACvC5B,sBAAsB;gBAACuC,SAAS;gBAAUtB;gBAAQmB;YAAS;QAC7D;QAEA,MAAMI,qBAAqB;YACzB;gBAACC,MAAM;gBAAUT,SAASF;YAAkB;YAC5C;gBAACW,MAAM;gBAAkBT,SAASF;YAAkB;SACrD;QACDD,qBAAqBtB,wBAAwBiC,oBAAoB;YAACF;QAAK;QAEvE,qBAAqB;QACrB,MAAM,EAACI,UAAU,EAAEC,oBAAoB,EAAC,GAAG,MAAMhD,0BAC/C6C,oBACAtB,SACA;YAACoB;QAAK;QAGR,IAAIK,qBAAqBC,MAAM,GAAG,GAAG;YACnC,MAAMnC,yBAAyB;gBAACQ;gBAAQE;gBAAgBwB;YAAoB;YAC5Ed,qBAAqB,CAAC;YACtBF,qBAAqB;QACvB;QAEA,IAAIe,WAAWE,MAAM,GAAG,KAAKjB,oBAAoB;YAC/C,MAAMkB,yBACJ,CAAC,mGAAmG,CAAC,GACrG,CAAC,yGAAyG,CAAC,GAC3G,GAAGH,WAAWI,GAAG,CAAC,CAACC,MAAQ,CAAC,GAAG,EAAEA,IAAIC,GAAG,CAAC,iBAAiB,EAAED,IAAIE,SAAS,CAAC,mBAAmB,EAAEF,IAAIG,MAAM,CAAC,CAAC,CAAC,EAAE1B,IAAI,CAAC,OAAO;YAE5H,0EAA0E;YAC1E,IAAIrC,mBAAmB,CAACgC,gBAAgB;gBACtC,MAAMgC,SAAS,MAAM7D,OAAO;oBAC1B8D,SAAS;wBACP;4BACEX,MAAM,CAAC,kFAAkF,CAAC;4BAC1FY,OAAO;wBACT;wBACA;4BACEZ,MAAM,CAAC,8BAA8B,CAAC;4BACtCY,OAAO;wBACT;wBACA;4BACEZ,MAAM,CAAC,eAAe,CAAC;4BACvBY,OAAO;wBACT;wBACA;4BAACZ,MAAM;4BAAUY,OAAO;wBAAQ;qBACjC;oBACDC,SAAS;oBACTC,SAASvE,UACP,UACA,GAAGK,WAAWmE,OAAO,CAAC,CAAC,EAAEX,uBAAuB,2DAA2D,CAAC;gBAEhH;gBAEA,IAAIM,WAAW,UAAU;oBACvBlC,OAAOwC,KAAK,CAAC,mCAAmC;wBAACC,MAAM;oBAAC;oBACxD;gBACF;gBAEA,IAAIP,WAAW,aAAaA,WAAW,uBAAuB;oBAC5D,MAAMpD,gBACJ;wBACE4D,gBAAgB,AAAC,CAAA,MAAM7D,wBAAwBoB,SAAS;4BAAC0C,aAAa;wBAAK,EAAC,EAAGC,MAAM;wBACrFC,UAAUpB,WAAWI,GAAG,CAAC,CAACiB,MAAQ;gCAACA,IAAIf,GAAG;gCAAEe,IAAIb,MAAM;6BAAC;oBACzD,GACA;wBAACjC;wBAAQC;oBAAO;oBAGlB,IAAIiC,WAAW,WAAW;wBACxB;oBACF;gBACF;YACF,OAAO;gBACL,0DAA0D;gBAC1DlC,OAAO+C,IAAI,CAACnB;YACd;QACF;IACF;IAEA,MAAMoB,aAAazD;IACnB,IAAIyD,WAAWrB,MAAM,GAAG,GAAG;QACzB3B,OAAOiB,GAAG,CAAC;QACX,KAAK,MAAMgC,OAAOD,WAAY;YAC5BhD,OAAOiB,GAAG,CAAC,CAAC,EAAE,EAAEgC,KAAK;QACvB;QACAjD,OAAOiB,GAAG,CAAC;IACb;IAEA,IAAIiC,cAAc;IAClB,IAAI1C,cAAcH,oBAAoB,CAACH,kBAAkBhC,iBAAiB;QACxEgF,cAAc,MAAM/E,QAAQ;YAC1BkE,SAAS;YACTC,SAAS,CAAC,8CAA8C,EAAE9B,UAAU,QAAQ,CAAC;QAC/E;IACF;IAEA,uCAAuC;IACvC,MAAM2C,WAAW9D,kBAAkBQ,WAAW,UAAUG;IAExD,IAAIoD;IACJ,IAAIF,aAAa;QACftD,MAAMyD,KAAK,CAAC;QACZD,OAAO9E,QAAQ,uBAAuB+E,KAAK;QAC3C,MAAMxF,GAAG2C,WAAW;YAAC8C,OAAO;YAAMC,WAAW;QAAI;QACjD,MAAMC,gBAAgB5D,MAAM6D,GAAG,CAAC;QAChCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEF,cAAcG,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;IACd;IAEAR,OAAO9E,QAAQ,CAAC,mBAAmB,CAAC,EAAE+E,KAAK;IAE3C,MAAMQ,QAAQ7F,kBAAkB6F,KAAK,CAACrF;IACtCqF,MAAMR,KAAK;IAEX,IAAIS;IAEJ,IAAIpD,oBAAoB;QACtBoD,YAAY;YACVC,SAAS;gBACP,GAAI,MAAM7E,wBAAwB;oBAACiE;oBAAUa,KAAK/D;oBAASgE,OAAO;oBAAOzD;gBAAS,EAAE;gBACpF,GAAGI,kBAAkB;YACvB;QACF;IACF;IAEA,IAAI;QACFhB,MAAMyD,KAAK,CAAC;QAEZ,MAAMa,SAAS,MAAMjF,iBAAiB;YACpCkE;YACAa,KAAK/D;YACL6D;YACAK,QAAQhE,QAAQL,MAAMqE,MAAM;YAC5B3D;YACA4D,eACEvE,aAAa,mBAAmBA,YAAYA,UAAUuE,aAAa,GAAGC;YACxEC,WAAWnE,QAAQL,KAAK,CAAC,cAAc;YACvCyE,MAAM1E,aAAa,UAAUA,YAAYA,UAAU0E,IAAI,GAAGF;QAC5D;QAEAR,MAAM5C,GAAG,CAAC;YACRuD,YAAYN,OAAOO,MAAM,CACtBC,OAAO,CAAC,CAACC,QAAUA,MAAMC,OAAO,CAACF,OAAO,CAAC,CAAC5C,MAAQA,IAAI+C,cAAc,GACpEC,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,GAAG;QACjC;QACA,MAAMC,gBAAgBrF,MAAM6D,GAAG,CAAC;QAEhCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEuB,cAActB,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;QAEZC,MAAMqB,QAAQ;QACd,IAAIpF,MAAMqF,KAAK,EAAE;YACfnF,OAAOiB,GAAG,CAAC;YACXjB,OAAOiB,GAAG,CAACtC,kBAAkBC,kBAAkBsF,OAAOO,MAAM,EAAEW,KAAK,CAAC,GAAG;QACzE;IACF,EAAE,OAAO5C,OAAO;QACdY,KAAKiC,IAAI;QACTxB,MAAMrB,KAAK,CAACA;QACZ,MAAMF,UAAUE,iBAAiBxB,QAAQwB,MAAMF,OAAO,GAAGgD,OAAO9C;QAChExD,WAAW,CAAC,6BAA6B,CAAC,EAAE;YAACwD;QAAK;QAClDxC,OAAOwC,KAAK,CAAC,CAAC,+BAA+B,EAAEF,SAAS,EAAE;YAACG,MAAM;QAAC;IACpE;AACF"}
@@ -1,7 +1,7 @@
1
- import path, { resolve } from 'node:path';
1
+ import path from 'node:path';
2
2
  import semver from 'semver';
3
3
  import { build } from 'vite';
4
- import { getLocalPackageVersion } from '../../util/getLocalPackageVersion.js';
4
+ import { getLocalPackageDir, getLocalPackageVersion } from '../../util/getLocalPackageVersion.js';
5
5
  import { createExternalFromImportMap } from './createExternalFromImportMap.js';
6
6
  // Directory where vendor packages will be stored
7
7
  const VENDOR_DIR = 'vendor';
@@ -75,11 +75,14 @@ const STYLED_COMPONENTS_IMPORTS = {
75
75
  throw new Error(`Version '${version}' of package '${packageName}' is not supported yet.`);
76
76
  }
77
77
  const subpaths = ranges[matchedRange];
78
+ // Resolve the actual package directory using Node module resolution,
79
+ // so that hoisted packages in monorepos/workspaces are found correctly
80
+ const packageDir = getLocalPackageDir(packageName, cwd);
78
81
  // Iterate over each subpath and its corresponding entry point
79
82
  for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)){
80
83
  const specifier = path.posix.join(packageName, subpath);
81
84
  const chunkName = path.posix.join(packageName, path.relative(packageName, specifier) || 'index');
82
- entry[chunkName] = resolve(`node_modules/${packageName}/${relativeEntryPoint}`);
85
+ entry[chunkName] = path.join(packageDir, relativeEntryPoint);
83
86
  imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`);
84
87
  }
85
88
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/buildVendorDependencies.ts"],"sourcesContent":["import path, {resolve} from 'node:path'\n\nimport semver from 'semver'\nimport {build} from 'vite'\n\nimport {getLocalPackageVersion} from '../../util/getLocalPackageVersion.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\n\n// Directory where vendor packages will be stored\nconst VENDOR_DIR = 'vendor'\n\n/**\n * A type representing the imports of vendor packages, defining specific entry\n * points for various versions and subpaths of the packages.\n *\n * The `VendorImports` object is used to build ESM browser-compatible versions\n * of the specified packages. This approach ensures that the appropriate version\n * and entry points are used for each package, enabling compatibility and proper\n * functionality in the browser environment.\n *\n * ## Rationale\n *\n * The rationale for this structure is to handle different versions of the\n * packages carefully, especially major versions. Major version bumps often\n * introduce breaking changes, so the module scheme for the package needs to be\n * checked when there is a major version update. However, minor and patch\n * versions are generally backward compatible, so they are handled more\n * leniently. By assuming that new minor versions are compatible, we avoid\n * unnecessary warnings and streamline the update process.\n *\n * If a new minor version introduces an additional subpath export within the\n * package of this version range, the corresponding package can add a more\n * specific version range that includes the new subpath. This design allows for\n * flexibility and ease of maintenance, ensuring that the latest features and\n * fixes are incorporated without extensive manual intervention.\n *\n * An additional subpath export within the package of this version range that\n * could cause the build to break if that new export is used, can be treated as\n * a bug fix. It might make more sense to our users that this new subpath isn't\n * supported yet until we address it as a bug fix. This approach helps maintain\n * stability and prevents unexpected issues during the build process.\n *\n * ## Structure\n * The `VendorImports` type is a nested object where:\n * - The keys at the first level represent the package names.\n * - The keys at the second level represent the version ranges (e.g., `^19.0.0`).\n * - The keys at the third level represent the subpaths within the package (e.g., `.` for the main entry point).\n * - The values at the third level are the relative paths to the corresponding entry points within the package.\n *\n * This structure allows for precise specification of the entry points for\n * different versions and subpaths, ensuring that the correct files are used\n * during the build process.\n */\ntype VendorImports = {\n [packageName: string]: {\n [versionRange: string]: {\n [subpath: string]: string\n }\n }\n}\n\n// Define the vendor packages and their corresponding versions and entry points\nconst VENDOR_IMPORTS: VendorImports = {\n react: {\n '^19.2.0': {\n '.': './cjs/react.production.js',\n './compiler-runtime': './cjs/react-compiler-runtime.production.js',\n './jsx-dev-runtime': './cjs/react-jsx-dev-runtime.production.js',\n './jsx-runtime': './cjs/react-jsx-runtime.production.js',\n './package.json': './package.json',\n },\n },\n 'react-dom': {\n '^19.2.0': {\n '.': './cjs/react-dom.production.js',\n './client': './cjs/react-dom-client.production.js',\n './package.json': './package.json',\n './server': './cjs/react-dom-server-legacy.browser.production.js',\n './server.browser': './cjs/react-dom-server-legacy.browser.production.js',\n './static': './cjs/react-dom-server.browser.production.js',\n './static.browser': './cjs/react-dom-server.browser.production.js',\n },\n },\n}\n\nconst STYLED_COMPONENTS_IMPORTS = {\n 'styled-components': {\n '^6.1.0': {\n '.': './dist/styled-components.browser.esm.js',\n './package.json': './package.json',\n },\n },\n}\n\ninterface VendorBuildOptions {\n basePath: string\n cwd: string\n isApp: boolean\n outputDir: string\n}\n\n/**\n * Builds the ESM browser compatible versions of the vendor packages\n * specified in VENDOR_IMPORTS. Returns the `imports` object of an import map.\n */\nexport async function buildVendorDependencies({\n basePath,\n cwd,\n isApp,\n outputDir,\n}: VendorBuildOptions): Promise<Record<string, string>> {\n const entry: Record<string, string> = {}\n const imports: Record<string, string> = {}\n\n // If we're building an app, we don't need to build the styled-components package\n const vendorImports = isApp ? VENDOR_IMPORTS : {...VENDOR_IMPORTS, ...STYLED_COMPONENTS_IMPORTS}\n\n // Iterate over each package and its version ranges in VENDOR_IMPORTS\n for (const [packageName, ranges] of Object.entries(vendorImports)) {\n const version = await getLocalPackageVersion(packageName, cwd)\n if (!version) {\n throw new Error(`Could not get version for '${packageName}'`)\n }\n\n // Sort version ranges in descending order\n const sortedRanges = Object.keys(ranges).toSorted((range1, range2) => {\n const min1 = semver.minVersion(range1)\n const min2 = semver.minVersion(range2)\n\n if (!min1) throw new Error(`Could not parse range '${range1}'`)\n if (!min2) throw new Error(`Could not parse range '${range2}'`)\n\n // sort them in reverse so we can rely on array `.find` below\n return semver.rcompare(min1.version, min2.version)\n })\n\n // Find the first version range that satisfies the package version\n const matchedRange = sortedRanges.find((range) => semver.satisfies(version, range))\n\n if (!matchedRange) {\n const min = semver.minVersion(sortedRanges.at(-1)!)\n if (!min) {\n throw new Error(`Could not find a minimum version for package '${packageName}'`)\n }\n\n if (semver.gt(min.version, version)) {\n throw new Error(`Package '${packageName}' requires at least ${min.version}.`)\n }\n\n throw new Error(`Version '${version}' of package '${packageName}' is not supported yet.`)\n }\n\n const subpaths = ranges[matchedRange]\n\n // Iterate over each subpath and its corresponding entry point\n for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)) {\n const specifier = path.posix.join(packageName, subpath)\n const chunkName = path.posix.join(\n packageName,\n path.relative(packageName, specifier) || 'index',\n )\n\n entry[chunkName] = resolve(`node_modules/${packageName}/${relativeEntryPoint}`)\n imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`)\n }\n }\n\n // removes the `RollupWatcher` type\n type BuildResult = Exclude<Awaited<ReturnType<typeof build>>, {close: unknown}>\n\n // Use Vite to build the packages into the output directory\n let buildResult = (await build({\n appType: 'custom',\n build: {\n commonjsOptions: {strictRequires: 'auto'},\n emptyOutDir: false, // Rely on CLI to do this\n lib: {entry, formats: ['es']},\n minify: true,\n outDir: path.join(outputDir, VENDOR_DIR),\n rollupOptions: {\n external: createExternalFromImportMap({imports}),\n output: {\n chunkFileNames: '[name]-[hash].mjs',\n entryFileNames: '[name]-[hash].mjs',\n exports: 'named',\n format: 'es',\n },\n treeshake: {preset: 'recommended'},\n },\n },\n // Define a custom cache directory so that sanity's vite cache\n // does not conflict with any potential local vite projects\n cacheDir: 'node_modules/.sanity/vite-vendor',\n configFile: false,\n define: {'process.env.NODE_ENV': JSON.stringify('production')},\n logLevel: 'silent',\n mode: 'production',\n root: cwd,\n })) as BuildResult\n\n buildResult = Array.isArray(buildResult) ? buildResult : [buildResult]\n\n // Create a map of the original import specifiers to their hashed filenames\n const hashedImports: Record<string, string> = {}\n const output = buildResult.flatMap((i) => i.output)\n\n for (const chunk of output) {\n if (chunk.type === 'asset') continue\n\n for (const [specifier, originalPath] of Object.entries(imports)) {\n if (originalPath.endsWith(`${chunk.name}.mjs`)) {\n hashedImports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, chunk.fileName)\n }\n }\n }\n\n return hashedImports\n}\n"],"names":["path","resolve","semver","build","getLocalPackageVersion","createExternalFromImportMap","VENDOR_DIR","VENDOR_IMPORTS","react","STYLED_COMPONENTS_IMPORTS","buildVendorDependencies","basePath","cwd","isApp","outputDir","entry","imports","vendorImports","packageName","ranges","Object","entries","version","Error","sortedRanges","keys","toSorted","range1","range2","min1","minVersion","min2","rcompare","matchedRange","find","range","satisfies","min","at","gt","subpaths","subpath","relativeEntryPoint","specifier","posix","join","chunkName","relative","buildResult","appType","commonjsOptions","strictRequires","emptyOutDir","lib","formats","minify","outDir","rollupOptions","external","output","chunkFileNames","entryFileNames","exports","format","treeshake","preset","cacheDir","configFile","define","JSON","stringify","logLevel","mode","root","Array","isArray","hashedImports","flatMap","i","chunk","type","originalPath","endsWith","name","fileName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/build/buildVendorDependencies.ts"],"sourcesContent":["import path from 'node:path'\n\nimport semver from 'semver'\nimport {build} from 'vite'\n\nimport {getLocalPackageDir, getLocalPackageVersion} from '../../util/getLocalPackageVersion.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\n\n// Directory where vendor packages will be stored\nconst VENDOR_DIR = 'vendor'\n\n/**\n * A type representing the imports of vendor packages, defining specific entry\n * points for various versions and subpaths of the packages.\n *\n * The `VendorImports` object is used to build ESM browser-compatible versions\n * of the specified packages. This approach ensures that the appropriate version\n * and entry points are used for each package, enabling compatibility and proper\n * functionality in the browser environment.\n *\n * ## Rationale\n *\n * The rationale for this structure is to handle different versions of the\n * packages carefully, especially major versions. Major version bumps often\n * introduce breaking changes, so the module scheme for the package needs to be\n * checked when there is a major version update. However, minor and patch\n * versions are generally backward compatible, so they are handled more\n * leniently. By assuming that new minor versions are compatible, we avoid\n * unnecessary warnings and streamline the update process.\n *\n * If a new minor version introduces an additional subpath export within the\n * package of this version range, the corresponding package can add a more\n * specific version range that includes the new subpath. This design allows for\n * flexibility and ease of maintenance, ensuring that the latest features and\n * fixes are incorporated without extensive manual intervention.\n *\n * An additional subpath export within the package of this version range that\n * could cause the build to break if that new export is used, can be treated as\n * a bug fix. It might make more sense to our users that this new subpath isn't\n * supported yet until we address it as a bug fix. This approach helps maintain\n * stability and prevents unexpected issues during the build process.\n *\n * ## Structure\n * The `VendorImports` type is a nested object where:\n * - The keys at the first level represent the package names.\n * - The keys at the second level represent the version ranges (e.g., `^19.0.0`).\n * - The keys at the third level represent the subpaths within the package (e.g., `.` for the main entry point).\n * - The values at the third level are the relative paths to the corresponding entry points within the package.\n *\n * This structure allows for precise specification of the entry points for\n * different versions and subpaths, ensuring that the correct files are used\n * during the build process.\n */\ntype VendorImports = {\n [packageName: string]: {\n [versionRange: string]: {\n [subpath: string]: string\n }\n }\n}\n\n// Define the vendor packages and their corresponding versions and entry points\nconst VENDOR_IMPORTS: VendorImports = {\n react: {\n '^19.2.0': {\n '.': './cjs/react.production.js',\n './compiler-runtime': './cjs/react-compiler-runtime.production.js',\n './jsx-dev-runtime': './cjs/react-jsx-dev-runtime.production.js',\n './jsx-runtime': './cjs/react-jsx-runtime.production.js',\n './package.json': './package.json',\n },\n },\n 'react-dom': {\n '^19.2.0': {\n '.': './cjs/react-dom.production.js',\n './client': './cjs/react-dom-client.production.js',\n './package.json': './package.json',\n './server': './cjs/react-dom-server-legacy.browser.production.js',\n './server.browser': './cjs/react-dom-server-legacy.browser.production.js',\n './static': './cjs/react-dom-server.browser.production.js',\n './static.browser': './cjs/react-dom-server.browser.production.js',\n },\n },\n}\n\nconst STYLED_COMPONENTS_IMPORTS = {\n 'styled-components': {\n '^6.1.0': {\n '.': './dist/styled-components.browser.esm.js',\n './package.json': './package.json',\n },\n },\n}\n\ninterface VendorBuildOptions {\n basePath: string\n cwd: string\n isApp: boolean\n outputDir: string\n}\n\n/**\n * Builds the ESM browser compatible versions of the vendor packages\n * specified in VENDOR_IMPORTS. Returns the `imports` object of an import map.\n */\nexport async function buildVendorDependencies({\n basePath,\n cwd,\n isApp,\n outputDir,\n}: VendorBuildOptions): Promise<Record<string, string>> {\n const entry: Record<string, string> = {}\n const imports: Record<string, string> = {}\n\n // If we're building an app, we don't need to build the styled-components package\n const vendorImports = isApp ? VENDOR_IMPORTS : {...VENDOR_IMPORTS, ...STYLED_COMPONENTS_IMPORTS}\n\n // Iterate over each package and its version ranges in VENDOR_IMPORTS\n for (const [packageName, ranges] of Object.entries(vendorImports)) {\n const version = await getLocalPackageVersion(packageName, cwd)\n if (!version) {\n throw new Error(`Could not get version for '${packageName}'`)\n }\n\n // Sort version ranges in descending order\n const sortedRanges = Object.keys(ranges).toSorted((range1, range2) => {\n const min1 = semver.minVersion(range1)\n const min2 = semver.minVersion(range2)\n\n if (!min1) throw new Error(`Could not parse range '${range1}'`)\n if (!min2) throw new Error(`Could not parse range '${range2}'`)\n\n // sort them in reverse so we can rely on array `.find` below\n return semver.rcompare(min1.version, min2.version)\n })\n\n // Find the first version range that satisfies the package version\n const matchedRange = sortedRanges.find((range) => semver.satisfies(version, range))\n\n if (!matchedRange) {\n const min = semver.minVersion(sortedRanges.at(-1)!)\n if (!min) {\n throw new Error(`Could not find a minimum version for package '${packageName}'`)\n }\n\n if (semver.gt(min.version, version)) {\n throw new Error(`Package '${packageName}' requires at least ${min.version}.`)\n }\n\n throw new Error(`Version '${version}' of package '${packageName}' is not supported yet.`)\n }\n\n const subpaths = ranges[matchedRange]\n\n // Resolve the actual package directory using Node module resolution,\n // so that hoisted packages in monorepos/workspaces are found correctly\n const packageDir = getLocalPackageDir(packageName, cwd)\n\n // Iterate over each subpath and its corresponding entry point\n for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)) {\n const specifier = path.posix.join(packageName, subpath)\n const chunkName = path.posix.join(\n packageName,\n path.relative(packageName, specifier) || 'index',\n )\n\n entry[chunkName] = path.join(packageDir, relativeEntryPoint)\n imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`)\n }\n }\n\n // removes the `RollupWatcher` type\n type BuildResult = Exclude<Awaited<ReturnType<typeof build>>, {close: unknown}>\n\n // Use Vite to build the packages into the output directory\n let buildResult = (await build({\n appType: 'custom',\n build: {\n commonjsOptions: {strictRequires: 'auto'},\n emptyOutDir: false, // Rely on CLI to do this\n lib: {entry, formats: ['es']},\n minify: true,\n outDir: path.join(outputDir, VENDOR_DIR),\n rollupOptions: {\n external: createExternalFromImportMap({imports}),\n output: {\n chunkFileNames: '[name]-[hash].mjs',\n entryFileNames: '[name]-[hash].mjs',\n exports: 'named',\n format: 'es',\n },\n treeshake: {preset: 'recommended'},\n },\n },\n // Define a custom cache directory so that sanity's vite cache\n // does not conflict with any potential local vite projects\n cacheDir: 'node_modules/.sanity/vite-vendor',\n configFile: false,\n define: {'process.env.NODE_ENV': JSON.stringify('production')},\n logLevel: 'silent',\n mode: 'production',\n root: cwd,\n })) as BuildResult\n\n buildResult = Array.isArray(buildResult) ? buildResult : [buildResult]\n\n // Create a map of the original import specifiers to their hashed filenames\n const hashedImports: Record<string, string> = {}\n const output = buildResult.flatMap((i) => i.output)\n\n for (const chunk of output) {\n if (chunk.type === 'asset') continue\n\n for (const [specifier, originalPath] of Object.entries(imports)) {\n if (originalPath.endsWith(`${chunk.name}.mjs`)) {\n hashedImports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, chunk.fileName)\n }\n }\n }\n\n return hashedImports\n}\n"],"names":["path","semver","build","getLocalPackageDir","getLocalPackageVersion","createExternalFromImportMap","VENDOR_DIR","VENDOR_IMPORTS","react","STYLED_COMPONENTS_IMPORTS","buildVendorDependencies","basePath","cwd","isApp","outputDir","entry","imports","vendorImports","packageName","ranges","Object","entries","version","Error","sortedRanges","keys","toSorted","range1","range2","min1","minVersion","min2","rcompare","matchedRange","find","range","satisfies","min","at","gt","subpaths","packageDir","subpath","relativeEntryPoint","specifier","posix","join","chunkName","relative","buildResult","appType","commonjsOptions","strictRequires","emptyOutDir","lib","formats","minify","outDir","rollupOptions","external","output","chunkFileNames","entryFileNames","exports","format","treeshake","preset","cacheDir","configFile","define","JSON","stringify","logLevel","mode","root","Array","isArray","hashedImports","flatMap","i","chunk","type","originalPath","endsWith","name","fileName"],"mappings":"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"}
@@ -6,11 +6,7 @@ export function getExtractOptions({ flags, projectRoot, schemaExtraction }) {
6
6
  if (pathFlag) {
7
7
  const resolved = resolve(join(projectRoot.directory, pathFlag));
8
8
  const isExistingDirectory = existsSync(resolved) && statSync(resolved).isDirectory();
9
- if (isExistingDirectory || !extname(resolved)) {
10
- outputPath = join(resolved, 'schema.json');
11
- } else {
12
- outputPath = resolved;
13
- }
9
+ outputPath = isExistingDirectory || !extname(resolved) ? join(resolved, 'schema.json') : resolved;
14
10
  } else {
15
11
  outputPath = resolve(join(projectRoot.directory, 'schema.json'));
16
12
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/getExtractOptions.ts"],"sourcesContent":["import {existsSync, statSync} from 'node:fs'\nimport {extname, join, resolve} from 'node:path'\n\nimport {type CliConfig, ProjectRootResult} from '@sanity/cli-core'\n\nimport {type ExtractSchemaCommand} from '../../commands/schema/extract.js'\n\nexport interface ExtractOptions {\n configPath: string\n enforceRequiredFields: boolean\n format: string\n outputPath: string\n watchPatterns: string[]\n workspace: string | undefined\n}\n\ninterface GetExtractionOptions {\n flags: ExtractSchemaCommand['flags']\n projectRoot: ProjectRootResult\n schemaExtraction: CliConfig['schemaExtraction']\n}\n\nexport function getExtractOptions({\n flags,\n projectRoot,\n schemaExtraction,\n}: GetExtractionOptions): ExtractOptions {\n const pathFlag = flags.path ?? schemaExtraction?.path\n let outputPath: string\n if (pathFlag) {\n const resolved = resolve(join(projectRoot.directory, pathFlag))\n const isExistingDirectory = existsSync(resolved) && statSync(resolved).isDirectory()\n\n if (isExistingDirectory || !extname(resolved)) {\n outputPath = join(resolved, 'schema.json')\n } else {\n outputPath = resolved\n }\n } else {\n outputPath = resolve(join(projectRoot.directory, 'schema.json'))\n }\n\n return {\n configPath: projectRoot.path,\n enforceRequiredFields:\n flags['enforce-required-fields'] ?? schemaExtraction?.enforceRequiredFields ?? false,\n format: flags.format ?? 'groq-type-nodes',\n outputPath,\n watchPatterns: flags['watch-patterns'] ?? schemaExtraction?.watchPatterns ?? [],\n workspace: flags.workspace ?? schemaExtraction?.workspace,\n }\n}\n"],"names":["existsSync","statSync","extname","join","resolve","getExtractOptions","flags","projectRoot","schemaExtraction","pathFlag","path","outputPath","resolved","directory","isExistingDirectory","isDirectory","configPath","enforceRequiredFields","format","watchPatterns","workspace"],"mappings":"AAAA,SAAQA,UAAU,EAAEC,QAAQ,QAAO,UAAS;AAC5C,SAAQC,OAAO,EAAEC,IAAI,EAAEC,OAAO,QAAO,YAAW;AAqBhD,OAAO,SAASC,kBAAkB,EAChCC,KAAK,EACLC,WAAW,EACXC,gBAAgB,EACK;IACrB,MAAMC,WAAWH,MAAMI,IAAI,IAAIF,kBAAkBE;IACjD,IAAIC;IACJ,IAAIF,UAAU;QACZ,MAAMG,WAAWR,QAAQD,KAAKI,YAAYM,SAAS,EAAEJ;QACrD,MAAMK,sBAAsBd,WAAWY,aAAaX,SAASW,UAAUG,WAAW;QAElF,IAAID,uBAAuB,CAACZ,QAAQU,WAAW;YAC7CD,aAAaR,KAAKS,UAAU;QAC9B,OAAO;YACLD,aAAaC;QACf;IACF,OAAO;QACLD,aAAaP,QAAQD,KAAKI,YAAYM,SAAS,EAAE;IACnD;IAEA,OAAO;QACLG,YAAYT,YAAYG,IAAI;QAC5BO,uBACEX,KAAK,CAAC,0BAA0B,IAAIE,kBAAkBS,yBAAyB;QACjFC,QAAQZ,MAAMY,MAAM,IAAI;QACxBP;QACAQ,eAAeb,KAAK,CAAC,iBAAiB,IAAIE,kBAAkBW,iBAAiB,EAAE;QAC/EC,WAAWd,MAAMc,SAAS,IAAIZ,kBAAkBY;IAClD;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/schema/getExtractOptions.ts"],"sourcesContent":["import {existsSync, statSync} from 'node:fs'\nimport {extname, join, resolve} from 'node:path'\n\nimport {type CliConfig, ProjectRootResult} from '@sanity/cli-core'\n\nimport {type ExtractSchemaCommand} from '../../commands/schema/extract.js'\n\nexport interface ExtractOptions {\n configPath: string\n enforceRequiredFields: boolean\n format: string\n outputPath: string\n watchPatterns: string[]\n workspace: string | undefined\n}\n\ninterface GetExtractionOptions {\n flags: ExtractSchemaCommand['flags']\n projectRoot: ProjectRootResult\n schemaExtraction: CliConfig['schemaExtraction']\n}\n\nexport function getExtractOptions({\n flags,\n projectRoot,\n schemaExtraction,\n}: GetExtractionOptions): ExtractOptions {\n const pathFlag = flags.path ?? schemaExtraction?.path\n let outputPath: string\n if (pathFlag) {\n const resolved = resolve(join(projectRoot.directory, pathFlag))\n const isExistingDirectory = existsSync(resolved) && statSync(resolved).isDirectory()\n\n outputPath =\n isExistingDirectory || !extname(resolved) ? join(resolved, 'schema.json') : resolved\n } else {\n outputPath = resolve(join(projectRoot.directory, 'schema.json'))\n }\n\n return {\n configPath: projectRoot.path,\n enforceRequiredFields:\n flags['enforce-required-fields'] ?? schemaExtraction?.enforceRequiredFields ?? false,\n format: flags.format ?? 'groq-type-nodes',\n outputPath,\n watchPatterns: flags['watch-patterns'] ?? schemaExtraction?.watchPatterns ?? [],\n workspace: flags.workspace ?? schemaExtraction?.workspace,\n }\n}\n"],"names":["existsSync","statSync","extname","join","resolve","getExtractOptions","flags","projectRoot","schemaExtraction","pathFlag","path","outputPath","resolved","directory","isExistingDirectory","isDirectory","configPath","enforceRequiredFields","format","watchPatterns","workspace"],"mappings":"AAAA,SAAQA,UAAU,EAAEC,QAAQ,QAAO,UAAS;AAC5C,SAAQC,OAAO,EAAEC,IAAI,EAAEC,OAAO,QAAO,YAAW;AAqBhD,OAAO,SAASC,kBAAkB,EAChCC,KAAK,EACLC,WAAW,EACXC,gBAAgB,EACK;IACrB,MAAMC,WAAWH,MAAMI,IAAI,IAAIF,kBAAkBE;IACjD,IAAIC;IACJ,IAAIF,UAAU;QACZ,MAAMG,WAAWR,QAAQD,KAAKI,YAAYM,SAAS,EAAEJ;QACrD,MAAMK,sBAAsBd,WAAWY,aAAaX,SAASW,UAAUG,WAAW;QAElFJ,aACEG,uBAAuB,CAACZ,QAAQU,YAAYT,KAAKS,UAAU,iBAAiBA;IAChF,OAAO;QACLD,aAAaP,QAAQD,KAAKI,YAAYM,SAAS,EAAE;IACnD;IAEA,OAAO;QACLG,YAAYT,YAAYG,IAAI;QAC5BO,uBACEX,KAAK,CAAC,0BAA0B,IAAIE,kBAAkBS,yBAAyB;QACjFC,QAAQZ,MAAMY,MAAM,IAAI;QACxBP;QACAQ,eAAeb,KAAK,CAAC,iBAAiB,IAAIE,kBAAkBW,iBAAiB,EAAE;QAC/EC,WAAWd,MAAMc,SAAS,IAAIZ,kBAAkBY;IAClD;AACF"}
@@ -1,23 +1,9 @@
1
1
  import { getGlobalCliClient, subdebug } from '@sanity/cli-core';
2
- import { createRequester } from '@sanity/cli-core/request';
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 MCP server.
37
+ * Validate an MCP token by checking it against the Sanity API.
52
38
  *
53
- * MCP tokens are scoped to mcp.sanity.io and are not valid against
54
- * api.sanity.io, so we validate against the MCP server itself.
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
- * Sends a minimal POST with just the Authorization header the server
57
- * checks auth before content negotiation, so a valid token gets 406
58
- * (missing Accept header) while an invalid token gets 401. This avoids
59
- * the cost of a full initialize handshake.
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 request = getMCPRequester();
64
- // Use a 2500ms timeout — long enough for VPN/proxy/distant-region latency,
65
- // short enough to not stall the init flow. If the request times out or the
66
- // server returns an unexpected status, we assume the token is valid rather
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
- // 401/403 are the only responses that definitively mean "bad token".
79
- // Everything else (406 = valid, 5xx = server issue, 2xx = unexpected)
80
- // is treated as "assume valid" — we'd rather skip a re-auth prompt
81
- // than force users to re-configure because of a transient server error.
82
- if (res.statusCode === 401 || res.statusCode === 403) {
83
- debug('MCP token validation failed with %d', res.statusCode);
84
- return false;
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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/mcp.ts"],"sourcesContent":["import {getGlobalCliClient, subdebug} from '@sanity/cli-core'\nimport {createRequester, type Requester} from '@sanity/cli-core/request'\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\nlet mcpRequester: Requester | undefined\n\nfunction getMCPRequester(): Requester {\n if (!mcpRequester) {\n mcpRequester = createRequester({\n middleware: {httpErrors: false, promise: {onlyBody: false}},\n })\n }\n return mcpRequester\n}\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 against the MCP server.\n *\n * MCP tokens are scoped to mcp.sanity.io and are not valid against\n * api.sanity.io, so we validate against the MCP server itself.\n *\n * Sends a minimal POST with just the Authorization header the server\n * checks auth before content negotiation, so a valid token gets 406\n * (missing Accept header) while an invalid token gets 401. This avoids\n * the cost of a full initialize handshake.\n *\n * @internal\n */\nexport async function validateMCPToken(token: string): Promise<boolean> {\n const request = getMCPRequester()\n\n // Use a 2500ms timeout long enough for VPN/proxy/distant-region latency,\n // short enough to not stall the init flow. If the request times out or the\n // server returns an unexpected status, we assume the token is valid rather\n // than falsely marking it as expired (see below).\n const res = await request({\n body: '{}',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n timeout: 2500,\n url: MCP_SERVER_URL,\n })\n\n // 401/403 are the only responses that definitively mean \"bad token\".\n // Everything else (406 = valid, 5xx = server issue, 2xx = unexpected)\n // is treated as \"assume valid\" — we'd rather skip a re-auth prompt\n // than force users to re-configure because of a transient server error.\n if (res.statusCode === 401 || res.statusCode === 403) {\n debug('MCP token validation failed with %d', res.statusCode)\n return false\n }\n\n return true\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","createRequester","MCP_API_VERSION","MCP_SERVER_URL","MCP_JOURNEY_API_VERSION","debug","mcpRequester","getMCPRequester","middleware","httpErrors","promise","onlyBody","createMCPToken","client","apiVersion","requireUser","sessionResponse","request","body","sourceId","withStamp","method","uri","tokenResponse","query","sid","token","validateMCPToken","res","headers","Authorization","timeout","url","statusCode","getPostInitPrompt"],"mappings":"AAAA,SAAQA,kBAAkB,EAAEC,QAAQ,QAAO,mBAAkB;AAC7D,SAAQC,eAAe,QAAuB,2BAA0B;AAExE,OAAO,MAAMC,kBAAkB,aAAY;AAC3C,OAAO,MAAMC,iBAAiB,wBAAuB;AACrD,OAAO,MAAMC,0BAA0B,cAAa;AAEpD,MAAMC,QAAQL,SAAS;AAEvB,IAAIM;AAEJ,SAASC;IACP,IAAI,CAACD,cAAc;QACjBA,eAAeL,gBAAgB;YAC7BO,YAAY;gBAACC,YAAY;gBAAOC,SAAS;oBAACC,UAAU;gBAAK;YAAC;QAC5D;IACF;IACA,OAAOL;AACT;AAMA;;;;;;;CAOC,GACD,OAAO,eAAeM;IACpB,MAAMC,SAAS,MAAMd,mBAAmB;QACtCe,YAAYZ;QACZa,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;;;;;;;;;;;;CAYC,GACD,OAAO,eAAeC,iBAAiBD,KAAa;IAClD,MAAMT,UAAUV;IAEhB,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,kDAAkD;IAClD,MAAMqB,MAAM,MAAMX,QAAQ;QACxBC,MAAM;QACNW,SAAS;YACPC,eAAe,CAAC,OAAO,EAAEJ,OAAO;YAChC,gBAAgB;QAClB;QACAL,QAAQ;QACRU,SAAS;QACTC,KAAK7B;IACP;IAEA,qEAAqE;IACrE,sEAAsE;IACtE,mEAAmE;IACnE,wEAAwE;IACxE,IAAIyB,IAAIK,UAAU,KAAK,OAAOL,IAAIK,UAAU,KAAK,KAAK;QACpD5B,MAAM,uCAAuCuB,IAAIK,UAAU;QAC3D,OAAO;IACT;IAEA,OAAO;AACT;AAEA;;;;CAIC,GACD,OAAO,eAAeC;IACpB,MAAMrB,SAAS,MAAMd,mBAAmB;QAACe,YAAYV;QAAyBW,aAAa;IAAK;IAChG,OAAO,MAAMF,OAAOI,OAAO,CAAgC;QACzDI,QAAQ;QACRU,SAAS;QACTT,KAAK;IACP;AACF"}
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"}
@@ -11,30 +11,43 @@ import { moduleResolve } from 'import-meta-resolve';
11
11
  * @internal
12
12
  */ export async function getLocalPackageVersion(moduleName, workDir) {
13
13
  try {
14
- // Handle import.meta.url being passed instead of a directory path
15
- const dir = workDir.startsWith('file://') ? dirname(fileURLToPath(workDir)) : workDir;
16
- const dirUrl = pathToFileURL(resolve(dir, 'noop.js'));
17
- let packageJsonUrl;
18
- try {
19
- packageJsonUrl = moduleResolve(`${moduleName}/package.json`, dirUrl);
20
- } catch (err) {
21
- if (isErrPackagePathNotExported(err)) {
22
- // Fallback: resolve main entry point and derive package root
23
- const mainUrl = moduleResolve(moduleName, dirUrl);
24
- const mainPath = fileURLToPath(mainUrl);
25
- const normalizedName = normalize(moduleName);
26
- const idx = mainPath.lastIndexOf(normalizedName);
27
- const moduleRoot = mainPath.slice(0, idx + normalizedName.length);
28
- packageJsonUrl = pathToFileURL(join(moduleRoot, 'package.json'));
29
- } else {
30
- throw err;
31
- }
32
- }
33
- return (await readPackageJson(packageJsonUrl)).version;
14
+ const packageDir = getLocalPackageDir(moduleName, workDir);
15
+ return (await readPackageJson(join(packageDir, 'package.json'))).version;
34
16
  } catch {
35
17
  return null;
36
18
  }
37
19
  }
20
+ /**
21
+ * Resolve the filesystem directory of a locally installed package using Node
22
+ * module resolution. Works correctly with hoisted packages in monorepos/workspaces,
23
+ * pnpm symlinks, and other non-standard node_modules layouts.
24
+ *
25
+ * @param moduleName - The name of the package in npm.
26
+ * @param workDir - The working directory to resolve the module from. (aka project root)
27
+ * @returns The absolute path to the package directory.
28
+ * @internal
29
+ */ export function getLocalPackageDir(moduleName, workDir) {
30
+ // Handle import.meta.url being passed instead of a directory path
31
+ const dir = workDir.startsWith('file://') ? dirname(fileURLToPath(workDir)) : workDir;
32
+ const dirUrl = pathToFileURL(resolve(dir, 'noop.js'));
33
+ try {
34
+ const packageJsonUrl = moduleResolve(`${moduleName}/package.json`, dirUrl);
35
+ return dirname(fileURLToPath(packageJsonUrl));
36
+ } catch (err) {
37
+ if (!isErrPackagePathNotExported(err)) {
38
+ throw err;
39
+ }
40
+ }
41
+ // Fallback: resolve main entry point and derive package root
42
+ const mainUrl = moduleResolve(moduleName, dirUrl);
43
+ const mainPath = fileURLToPath(mainUrl);
44
+ const normalizedName = normalize(moduleName);
45
+ const idx = mainPath.lastIndexOf(normalizedName);
46
+ if (idx === -1) {
47
+ throw new Error(`Could not determine package directory for '${moduleName}'`);
48
+ }
49
+ return mainPath.slice(0, idx + normalizedName.length);
50
+ }
38
51
  function isErrPackagePathNotExported(err) {
39
52
  return err instanceof Error && 'code' in err && err.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED';
40
53
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/getLocalPackageVersion.ts"],"sourcesContent":["import {dirname, join, normalize, resolve} from 'node:path'\nimport {fileURLToPath, pathToFileURL} from 'node:url'\n\nimport {readPackageJson} from '@sanity/cli-core'\nimport {moduleResolve} from 'import-meta-resolve'\n\n/**\n * Get the version of a package installed locally.\n *\n * @param moduleName - The name of the package in npm.\n * @param workDir - The working directory to resolve the module from. (aka project root)\n * @returns The version of the package installed locally.\n * @internal\n */\nexport async function getLocalPackageVersion(\n moduleName: string,\n workDir: string,\n): Promise<string | null> {\n try {\n // Handle import.meta.url being passed instead of a directory path\n const dir = workDir.startsWith('file://') ? dirname(fileURLToPath(workDir)) : workDir\n const dirUrl = pathToFileURL(resolve(dir, 'noop.js'))\n\n let packageJsonUrl: URL\n try {\n packageJsonUrl = moduleResolve(`${moduleName}/package.json`, dirUrl)\n } catch (err: unknown) {\n if (isErrPackagePathNotExported(err)) {\n // Fallback: resolve main entry point and derive package root\n const mainUrl = moduleResolve(moduleName, dirUrl)\n const mainPath = fileURLToPath(mainUrl)\n const normalizedName = normalize(moduleName)\n const idx = mainPath.lastIndexOf(normalizedName)\n const moduleRoot = mainPath.slice(0, idx + normalizedName.length)\n packageJsonUrl = pathToFileURL(join(moduleRoot, 'package.json'))\n } else {\n throw err\n }\n }\n\n return (await readPackageJson(packageJsonUrl)).version\n } catch {\n return null\n }\n}\n\nfunction isErrPackagePathNotExported(err: unknown): boolean {\n return err instanceof Error && 'code' in err && err.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED'\n}\n"],"names":["dirname","join","normalize","resolve","fileURLToPath","pathToFileURL","readPackageJson","moduleResolve","getLocalPackageVersion","moduleName","workDir","dir","startsWith","dirUrl","packageJsonUrl","err","isErrPackagePathNotExported","mainUrl","mainPath","normalizedName","idx","lastIndexOf","moduleRoot","slice","length","version","Error","code"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,IAAI,EAAEC,SAAS,EAAEC,OAAO,QAAO,YAAW;AAC3D,SAAQC,aAAa,EAAEC,aAAa,QAAO,WAAU;AAErD,SAAQC,eAAe,QAAO,mBAAkB;AAChD,SAAQC,aAAa,QAAO,sBAAqB;AAEjD;;;;;;;CAOC,GACD,OAAO,eAAeC,uBACpBC,UAAkB,EAClBC,OAAe;IAEf,IAAI;QACF,kEAAkE;QAClE,MAAMC,MAAMD,QAAQE,UAAU,CAAC,aAAaZ,QAAQI,cAAcM,YAAYA;QAC9E,MAAMG,SAASR,cAAcF,QAAQQ,KAAK;QAE1C,IAAIG;QACJ,IAAI;YACFA,iBAAiBP,cAAc,GAAGE,WAAW,aAAa,CAAC,EAAEI;QAC/D,EAAE,OAAOE,KAAc;YACrB,IAAIC,4BAA4BD,MAAM;gBACpC,6DAA6D;gBAC7D,MAAME,UAAUV,cAAcE,YAAYI;gBAC1C,MAAMK,WAAWd,cAAca;gBAC/B,MAAME,iBAAiBjB,UAAUO;gBACjC,MAAMW,MAAMF,SAASG,WAAW,CAACF;gBACjC,MAAMG,aAAaJ,SAASK,KAAK,CAAC,GAAGH,MAAMD,eAAeK,MAAM;gBAChEV,iBAAiBT,cAAcJ,KAAKqB,YAAY;YAClD,OAAO;gBACL,MAAMP;YACR;QACF;QAEA,OAAO,AAAC,CAAA,MAAMT,gBAAgBQ,eAAc,EAAGW,OAAO;IACxD,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAAST,4BAA4BD,GAAY;IAC/C,OAAOA,eAAeW,SAAS,UAAUX,OAAOA,IAAIY,IAAI,KAAK;AAC/D"}
1
+ {"version":3,"sources":["../../src/util/getLocalPackageVersion.ts"],"sourcesContent":["import {dirname, join, normalize, resolve} from 'node:path'\nimport {fileURLToPath, pathToFileURL} from 'node:url'\n\nimport {readPackageJson} from '@sanity/cli-core'\nimport {moduleResolve} from 'import-meta-resolve'\n\n/**\n * Get the version of a package installed locally.\n *\n * @param moduleName - The name of the package in npm.\n * @param workDir - The working directory to resolve the module from. (aka project root)\n * @returns The version of the package installed locally.\n * @internal\n */\nexport async function getLocalPackageVersion(\n moduleName: string,\n workDir: string,\n): Promise<string | null> {\n try {\n const packageDir = getLocalPackageDir(moduleName, workDir)\n return (await readPackageJson(join(packageDir, 'package.json'))).version\n } catch {\n return null\n }\n}\n\n/**\n * Resolve the filesystem directory of a locally installed package using Node\n * module resolution. Works correctly with hoisted packages in monorepos/workspaces,\n * pnpm symlinks, and other non-standard node_modules layouts.\n *\n * @param moduleName - The name of the package in npm.\n * @param workDir - The working directory to resolve the module from. (aka project root)\n * @returns The absolute path to the package directory.\n * @internal\n */\nexport function getLocalPackageDir(moduleName: string, workDir: string): string {\n // Handle import.meta.url being passed instead of a directory path\n const dir = workDir.startsWith('file://') ? dirname(fileURLToPath(workDir)) : workDir\n const dirUrl = pathToFileURL(resolve(dir, 'noop.js'))\n\n try {\n const packageJsonUrl = moduleResolve(`${moduleName}/package.json`, dirUrl)\n return dirname(fileURLToPath(packageJsonUrl))\n } catch (err: unknown) {\n if (!isErrPackagePathNotExported(err)) {\n throw err\n }\n }\n\n // Fallback: resolve main entry point and derive package root\n const mainUrl = moduleResolve(moduleName, dirUrl)\n const mainPath = fileURLToPath(mainUrl)\n const normalizedName = normalize(moduleName)\n const idx = mainPath.lastIndexOf(normalizedName)\n if (idx === -1) {\n throw new Error(`Could not determine package directory for '${moduleName}'`)\n }\n return mainPath.slice(0, idx + normalizedName.length)\n}\n\nfunction isErrPackagePathNotExported(err: unknown): boolean {\n return err instanceof Error && 'code' in err && err.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED'\n}\n"],"names":["dirname","join","normalize","resolve","fileURLToPath","pathToFileURL","readPackageJson","moduleResolve","getLocalPackageVersion","moduleName","workDir","packageDir","getLocalPackageDir","version","dir","startsWith","dirUrl","packageJsonUrl","err","isErrPackagePathNotExported","mainUrl","mainPath","normalizedName","idx","lastIndexOf","Error","slice","length","code"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,IAAI,EAAEC,SAAS,EAAEC,OAAO,QAAO,YAAW;AAC3D,SAAQC,aAAa,EAAEC,aAAa,QAAO,WAAU;AAErD,SAAQC,eAAe,QAAO,mBAAkB;AAChD,SAAQC,aAAa,QAAO,sBAAqB;AAEjD;;;;;;;CAOC,GACD,OAAO,eAAeC,uBACpBC,UAAkB,EAClBC,OAAe;IAEf,IAAI;QACF,MAAMC,aAAaC,mBAAmBH,YAAYC;QAClD,OAAO,AAAC,CAAA,MAAMJ,gBAAgBL,KAAKU,YAAY,gBAAe,EAAGE,OAAO;IAC1E,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASD,mBAAmBH,UAAkB,EAAEC,OAAe;IACpE,kEAAkE;IAClE,MAAMI,MAAMJ,QAAQK,UAAU,CAAC,aAAaf,QAAQI,cAAcM,YAAYA;IAC9E,MAAMM,SAASX,cAAcF,QAAQW,KAAK;IAE1C,IAAI;QACF,MAAMG,iBAAiBV,cAAc,GAAGE,WAAW,aAAa,CAAC,EAAEO;QACnE,OAAOhB,QAAQI,cAAca;IAC/B,EAAE,OAAOC,KAAc;QACrB,IAAI,CAACC,4BAA4BD,MAAM;YACrC,MAAMA;QACR;IACF;IAEA,6DAA6D;IAC7D,MAAME,UAAUb,cAAcE,YAAYO;IAC1C,MAAMK,WAAWjB,cAAcgB;IAC/B,MAAME,iBAAiBpB,UAAUO;IACjC,MAAMc,MAAMF,SAASG,WAAW,CAACF;IACjC,IAAIC,QAAQ,CAAC,GAAG;QACd,MAAM,IAAIE,MAAM,CAAC,2CAA2C,EAAEhB,WAAW,CAAC,CAAC;IAC7E;IACA,OAAOY,SAASK,KAAK,CAAC,GAAGH,MAAMD,eAAeK,MAAM;AACtD;AAEA,SAASR,4BAA4BD,GAAY;IAC/C,OAAOA,eAAeO,SAAS,UAAUP,OAAOA,IAAIU,IAAI,KAAK;AAC/D"}