@sanity/cli 7.4.1 → 7.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/build/buildApp.js +1 -3
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +1 -3
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/mcp/editorConfigs.js +11 -5
- package/dist/actions/mcp/editorConfigs.js.map +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +8 -8
- package/templates/app-quickstart/.claude/skills/sanity-app-sdk/SKILL.md +56 -0
- package/templates/app-quickstart/AGENTS.md +40 -0
- package/templates/app-quickstart/README.md +22 -0
- package/templates/app-quickstart/src/ExampleComponent.css +6 -0
- package/templates/app-quickstart/src/ExampleComponent.tsx +30 -9
- package/templates/app-sanity-ui/.claude/skills/sanity-app-sdk/SKILL.md +60 -0
- package/templates/app-sanity-ui/AGENTS.md +44 -0
- package/templates/app-sanity-ui/README.md +23 -0
- package/templates/app-sanity-ui/src/ExampleComponent.tsx +8 -5
- package/dist/actions/build/buildStaticFiles.js +0 -144
- package/dist/actions/build/buildStaticFiles.js.map +0 -1
- package/dist/util/formatSize.js +0 -10
- package/dist/util/formatSize.js.map +0 -1
- package/dist/util/moduleFormatUtils.js +0 -18
- package/dist/util/moduleFormatUtils.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { rm } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
|
-
import { AppBuildTrace, buildDebug, getAutoUpdatesCssUrls, getAutoUpdatesImportMap, resolveVendorBuildConfig } from '@sanity/cli-build/_internal/build';
|
|
4
|
+
import { AppBuildTrace, buildDebug, buildStaticFiles, formatModuleSizes, getAutoUpdatesCssUrls, getAutoUpdatesImportMap, resolveVendorBuildConfig, sortModulesBySize } from '@sanity/cli-build/_internal/build';
|
|
5
5
|
import { getAppEnvironmentVariables } from '@sanity/cli-build/_internal/env';
|
|
6
6
|
import { getCliTelemetry, getLocalPackageVersion, getTimer, isInteractive } from '@sanity/cli-core';
|
|
7
7
|
import { confirm, logSymbols, spinner } from '@sanity/cli-core/ux';
|
|
@@ -9,9 +9,7 @@ import { resolveWorkbenchApp } from '@sanity/workbench-cli/build';
|
|
|
9
9
|
import { parse as semverParse } from 'semver';
|
|
10
10
|
import { getAppId } from '../../util/appId.js';
|
|
11
11
|
import { compareDependencyVersions } from '../../util/compareDependencyVersions.js';
|
|
12
|
-
import { formatModuleSizes, sortModulesBySize } from '../../util/moduleFormatUtils.js';
|
|
13
12
|
import { warnAboutMissingAppId } from '../../util/warnAboutMissingAppId.js';
|
|
14
|
-
import { buildStaticFiles } from './buildStaticFiles.js';
|
|
15
13
|
import { determineBasePath } from './determineBasePath.js';
|
|
16
14
|
import { handlePrereleaseVersions } from './handlePrereleaseVersions.js';
|
|
17
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/buildApp.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {\n AppBuildTrace,\n buildDebug,\n getAutoUpdatesCssUrls,\n getAutoUpdatesImportMap,\n resolveVendorBuildConfig,\n} from '@sanity/cli-build/_internal/build'\nimport {getAppEnvironmentVariables} from '@sanity/cli-build/_internal/env'\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {getAppId} from '../../util/appId.js'\nimport {\n compareDependencyVersions,\n CompareDependencyVersionsResult,\n} from '../../util/compareDependencyVersions.js'\nimport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {buildStaticFiles} from './buildStaticFiles.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {type BuildOptions} from './types.js'\n\ninterface InternalBuildOptions {\n appId: string | undefined\n appTitle: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n entry: string | undefined\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n services: DefineAppInput['services']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n views: DefineAppInput['views']\n vite: UserViteConfig | undefined\n workDir: string\n}\n\n/**\n * Build the Sanity app.\n *\n * @internal\n */\nexport async function buildApp(options: BuildOptions): Promise<void> {\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const app = cliConfig && 'app' in cliConfig ? cliConfig.app : undefined\n // `views`/`services` live on the branded `unstable_defineApp` result, not the\n // legacy `app` config object — resolve the workbench capability to read them.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n await internalBuildApp({\n appId,\n appTitle: app?.title,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\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: 'app', output})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'app', output),\n entry: app?.entry,\n isWorkbenchApp: !!workbench,\n minify: flags.minify,\n outDir,\n output,\n reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n schemaExtraction: cliConfig?.schemaExtraction,\n services: workbench?.services,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: flags.yes,\n views: workbench?.views,\n vite: cliConfig.vite,\n workDir,\n })\n}\n\n/**\n * Internal build app that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nasync function internalBuildApp(options: InternalBuildOptions): Promise<void> {\n buildDebug(`Building app`)\n\n const {appId, determineBasePath, outDir, output, workDir} = options\n let {autoUpdatesEnabled} = options\n const unattendedMode = options.unattendedMode\n\n const timer = getTimer()\n\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n const installedSdkVersion = await getLocalPackageVersion('@sanity/sdk-react', workDir)\n const installedSanityVersion = await getLocalPackageVersion('sanity', workDir)\n\n if (!installedSdkVersion) {\n output.error(`Failed to find installed @sanity/sdk-react version`, {exit: 1})\n return\n }\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSDKVersion = semverParse(installedSdkVersion)?.version\n if (!cleanSDKVersion) {\n output.error(`Failed to parse installed SDK version: ${installedSdkVersion}`, {exit: 1})\n return\n }\n\n // Sanity might not be installed, but if it is, we want to auto update it.\n const cleanSanityVersion = semverParse(installedSanityVersion)?.version\n\n const autoUpdatedPackages = [\n {name: '@sanity/sdk', version: cleanSDKVersion},\n {name: '@sanity/sdk-react', version: cleanSDKVersion},\n ...(cleanSanityVersion\n ? [{cssFile: 'index.css', name: 'sanity' as const, version: cleanSanityVersion}]\n : []),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(autoUpdatedPackages, {appId})\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(autoUpdatedPackages, {appId})\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n // Warn if auto updates enabled but no appId configured.\n options.checkAppId()\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(autoUpdatedPackages)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\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 shouldContinue = await confirm({\n default: false,\n message: styleText('yellow', `${versionMismatchWarning} \\n\\nContinue anyway?`),\n })\n\n if (!shouldContinue) {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = Object.keys(getAppEnvironmentVariables())\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) output.log(`- ${key}`)\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 const basePath = determineBasePath()\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(`Building Sanity application`).start()\n\n const trace = getCliTelemetry().trace(AppBuildTrace)\n trace.start()\n\n let autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: true}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n appTitle: options.appTitle,\n autoUpdates,\n basePath,\n cwd: workDir,\n entry: options.entry,\n isApp: true,\n isWorkbenchApp: options.isWorkbenchApp,\n minify: options.minify,\n outputDir,\n reactCompiler: options.reactCompiler,\n schemaExtraction: options.schemaExtraction,\n services: options.services,\n sourceMap: options.sourceMap,\n views: options.views,\n vite: options.vite,\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 application (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n if (options.stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n\n trace.complete()\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 application`, {error})\n output.error(`Failed to build Sanity application: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","AppBuildTrace","buildDebug","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","resolveVendorBuildConfig","getAppEnvironmentVariables","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","spinner","resolveWorkbenchApp","parse","semverParse","getAppId","compareDependencyVersions","formatModuleSizes","sortModulesBySize","warnAboutMissingAppId","buildStaticFiles","determineBasePath","handlePrereleaseVersions","buildApp","options","cliConfig","flags","outDir","output","workDir","app","undefined","workbench","appId","internalBuildApp","appTitle","title","autoUpdatesEnabled","checkAppId","calledFromDeploy","appType","packages","entry","isWorkbenchApp","minify","reactCompiler","schemaExtraction","services","sourceMap","Boolean","stats","unattendedMode","yes","views","vite","timer","defaultOutputDir","resolve","join","outputDir","installedSdkVersion","installedSanityVersion","error","exit","autoUpdatesImports","autoUpdatesCssUrls","cleanSDKVersion","version","cleanSanityVersion","autoUpdatedPackages","name","cssFile","log","info","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","shouldContinue","default","message","warn","envVarKeys","Object","keys","key","shouldClean","basePath","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","cssUrls","imports","vendor","cwd","isApp","bundle","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","slice","complete","fail","Error","String"],"mappings":"AAAA,SAAQA,EAAE,QAAO,mBAAkB;AACnC,OAAOC,UAAU,YAAW;AAC5B,SAAQC,SAAS,QAAO,YAAW;AAEnC,SACEC,aAAa,EACbC,UAAU,EACVC,qBAAqB,EACrBC,uBAAuB,EACvBC,wBAAwB,QACnB,oCAAmC;AAC1C,SAAQC,0BAA0B,QAAO,kCAAiC;AAC1E,SAEEC,eAAe,EACfC,sBAAsB,EACtBC,QAAQ,EACRC,aAAa,QAGR,mBAAkB;AACzB,SAAQC,OAAO,EAAEC,UAAU,EAAEC,OAAO,QAA6B,sBAAqB;AAEtF,SAAQC,mBAAmB,QAAO,8BAA6B;AAC/D,SAAQC,SAASC,WAAW,QAAO,SAAQ;AAE3C,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SACEC,yBAAyB,QAEpB,0CAAyC;AAChD,SAAQC,iBAAiB,EAAEC,iBAAiB,QAAO,kCAAiC;AACpF,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,gBAAgB,QAAO,wBAAuB;AACtD,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,wBAAwB,QAAO,gCAA+B;AA4BtE;;;;CAIC,GACD,OAAO,eAAeC,SAASC,OAAqB;IAClD,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAEpD,MAAMM,MAAML,aAAa,SAASA,YAAYA,UAAUK,GAAG,GAAGC;IAC9D,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAMC,YAAYpB,oBAAoBa;IAEtC,MAAMQ,QAAQlB,SAASU;IAEvB,MAAMS,iBAAiB;QACrBD;QACAE,UAAUL,KAAKM;QACfC,oBAAoBb,QAAQa,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACL,SAAS,CAACT,QAAQe,gBAAgB,EAAE;gBACvCpB,sBAAsB;oBAACqB,SAAS;oBAAOZ;gBAAM;YAC/C;QACF;QACAZ,2BAA2B,CAACyB,WAAazB,0BAA0ByB,UAAUZ,SAAS;gBAACI;YAAK;QAC5FZ,mBAAmB,IAAMA,kBAAkBI,WAAW,OAAOG;QAC7Dc,OAAOZ,KAAKY;QACZC,gBAAgB,CAAC,CAACX;QAClBY,QAAQlB,MAAMkB,MAAM;QACpBjB;QACAC;QACAiB,eAAepB,aAAa,mBAAmBA,YAAYA,UAAUoB,aAAa,GAAGd;QACrFe,kBAAkBrB,WAAWqB;QAC7BC,UAAUf,WAAWe;QACrBC,WAAWC,QAAQvB,KAAK,CAAC,cAAc;QACvCwB,OAAOxB,MAAMwB,KAAK;QAClBC,gBAAgBzB,MAAM0B,GAAG;QACzBC,OAAOrB,WAAWqB;QAClBC,MAAM7B,UAAU6B,IAAI;QACpBzB;IACF;AACF;AAEA;;;CAGC,GACD,eAAeK,iBAAiBV,OAA6B;IAC3DxB,WAAW,CAAC,YAAY,CAAC;IAEzB,MAAM,EAACiC,KAAK,EAAEZ,iBAAiB,EAAEM,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAC5D,IAAI,EAACa,kBAAkB,EAAC,GAAGb;IAC3B,MAAM2B,iBAAiB3B,QAAQ2B,cAAc;IAE7C,MAAMI,QAAQhD;IAEd,MAAMiD,mBAAmB3D,KAAK4D,OAAO,CAAC5D,KAAK6D,IAAI,CAAC7B,SAAS;IACzD,MAAM8B,YAAY9D,KAAK4D,OAAO,CAAC9B,UAAU6B;IAEzC,MAAMI,sBAAsB,MAAMtD,uBAAuB,qBAAqBuB;IAC9E,MAAMgC,yBAAyB,MAAMvD,uBAAuB,UAAUuB;IAEtE,IAAI,CAAC+B,qBAAqB;QACxBhC,OAAOkC,KAAK,CAAC,CAAC,kDAAkD,CAAC,EAAE;YAACC,MAAM;QAAC;QAC3E;IACF;IAEA,IAAIC,qBAAqB,CAAC;IAC1B,IAAIC,qBAA+B,EAAE;IAErC,IAAI5B,oBAAoB;QACtB,iFAAiF;QACjF,MAAM6B,kBAAkBpD,YAAY8C,sBAAsBO;QAC1D,IAAI,CAACD,iBAAiB;YACpBtC,OAAOkC,KAAK,CAAC,CAAC,uCAAuC,EAAEF,qBAAqB,EAAE;gBAACG,MAAM;YAAC;YACtF;QACF;QAEA,0EAA0E;QAC1E,MAAMK,qBAAqBtD,YAAY+C,yBAAyBM;QAEhE,MAAME,sBAAsB;YAC1B;gBAACC,MAAM;gBAAeH,SAASD;YAAe;YAC9C;gBAACI,MAAM;gBAAqBH,SAASD;YAAe;eAChDE,qBACA;gBAAC;oBAACG,SAAS;oBAAaD,MAAM;oBAAmBH,SAASC;gBAAkB;aAAE,GAC9E,EAAE;SACP;QACDJ,qBAAqB9D,wBAAwBmE,qBAAqB;YAACpC;QAAK;QACxEgC,qBAAqBhE,sBAAsBoE,qBAAqB;YAACpC;QAAK;QAEtEL,OAAO4C,GAAG,CAAC,GAAG9D,WAAW+D,IAAI,CAAC,mCAAmC,CAAC;QAElE,wDAAwD;QACxDjD,QAAQc,UAAU;QAElB,qBAAqB;QACrB,MAAM,EAACoC,UAAU,EAAEC,oBAAoB,EAAC,GACtC,MAAMnD,QAAQR,yBAAyB,CAACqD;QAE1C,IAAIM,qBAAqBC,MAAM,GAAG,GAAG;YACnC,MAAMtD,yBAAyB;gBAACM;gBAAQuB;gBAAgBwB;YAAoB;YAC5EX,qBAAqB,CAAC;YACtBC,qBAAqB,EAAE;YACvB5B,qBAAqB;QACvB;QAEA,IAAIqC,WAAWE,MAAM,GAAG,KAAKvC,oBAAoB;YAC/C,MAAMwC,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,EAAExB,IAAI,CAAC,OAAO;YAE5H,0EAA0E;YAC1E,IAAIlD,mBAAmB,CAAC2C,gBAAgB;gBACtC,MAAMgC,iBAAiB,MAAM1E,QAAQ;oBACnC2E,SAAS;oBACTC,SAASvF,UAAU,UAAU,GAAG+E,uBAAuB,qBAAqB,CAAC;gBAC/E;gBAEA,IAAI,CAACM,gBAAgB;oBACnBvD,OAAOkC,KAAK,CAAC,mCAAmC;wBAACC,MAAM;oBAAC;oBACxD;gBACF;YACF,OAAO;gBACL,0DAA0D;gBAC1DnC,OAAO0D,IAAI,CAACT;YACd;QACF;IACF;IAEA,MAAMU,aAAaC,OAAOC,IAAI,CAACrF;IAC/B,IAAImF,WAAWX,MAAM,GAAG,GAAG;QACzBhD,OAAO4C,GAAG,CAAC;QACX,KAAK,MAAMkB,OAAOH,WAAY3D,OAAO4C,GAAG,CAAC,CAAC,EAAE,EAAEkB,KAAK;QACnD9D,OAAO4C,GAAG,CAAC;IACb;IAEA,IAAImB,cAAc;IAClB,IAAIhC,cAAcH,oBAAoB,CAACL,kBAAkB3C,iBAAiB;QACxEmF,cAAc,MAAMlF,QAAQ;YAC1B2E,SAAS;YACTC,SAAS,CAAC,8CAA8C,EAAE1B,UAAU,QAAQ,CAAC;QAC/E;IACF;IAEA,MAAMiC,WAAWvE;IAEjB,IAAIwE;IACJ,IAAIF,aAAa;QACfpC,MAAMuC,KAAK,CAAC;QACZD,OAAOlF,QAAQ,uBAAuBmF,KAAK;QAC3C,MAAMlG,GAAG+D,WAAW;YAACoC,OAAO;YAAMC,WAAW;QAAI;QACjD,MAAMC,gBAAgB1C,MAAM2C,GAAG,CAAC;QAChCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEF,cAAcG,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;IACd;IAEAR,OAAOlF,QAAQ,CAAC,2BAA2B,CAAC,EAAEmF,KAAK;IAEnD,MAAMQ,QAAQjG,kBAAkBiG,KAAK,CAACvG;IACtCuG,MAAMR,KAAK;IAEX,IAAIS;IACJ,IAAIlE,sBAAsB,CAACb,QAAQmB,cAAc,EAAE;QACjD4D,cAAc;YACZC,SAASvC;YACTwC,SAASzC;YACT0C,QAAQ,MAAMvG,yBAAyB;gBAACwG,KAAK9E;gBAAS+E,OAAO;YAAI;QACnE;IACF;IAEA,IAAI;QACFrD,MAAMuC,KAAK,CAAC;QAEZ,MAAMe,SAAS,MAAMzF,iBAAiB;YACpCe,UAAUX,QAAQW,QAAQ;YAC1BoE;YACAX;YACAe,KAAK9E;YACLa,OAAOlB,QAAQkB,KAAK;YACpBkE,OAAO;YACPjE,gBAAgBnB,QAAQmB,cAAc;YACtCC,QAAQpB,QAAQoB,MAAM;YACtBe;YACAd,eAAerB,QAAQqB,aAAa;YACpCC,kBAAkBtB,QAAQsB,gBAAgB;YAC1CC,UAAUvB,QAAQuB,QAAQ;YAC1BC,WAAWxB,QAAQwB,SAAS;YAC5BK,OAAO7B,QAAQ6B,KAAK;YACpBC,MAAM9B,QAAQ8B,IAAI;QACpB;QAEAgD,MAAM9B,GAAG,CAAC;YACRsC,YAAYD,OAAOE,MAAM,CACtBC,OAAO,CAAC,CAACC,QAAUA,MAAMC,OAAO,CAACF,OAAO,CAAC,CAACjC,MAAQA,IAAIoC,cAAc,GACpEC,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,GAAG;QACjC;QACA,MAAMC,gBAAgBhE,MAAM2C,GAAG,CAAC;QAEhCL,KAAKM,IAAI,GAAG,CAAC,0BAA0B,EAAEoB,cAAcnB,OAAO,CAAC,GAAG,GAAG,CAAC;QACtEP,KAAKQ,OAAO;QAEZ,IAAI7E,QAAQ0B,KAAK,EAAE;YACjBtB,OAAO4C,GAAG,CAAC;YACX5C,OAAO4C,GAAG,CAACvD,kBAAkBC,kBAAkB2F,OAAOE,MAAM,EAAES,KAAK,CAAC,GAAG;QACzE;QAEAlB,MAAMmB,QAAQ;IAChB,EAAE,OAAO3D,OAAO;QACd+B,KAAK6B,IAAI;QACTpB,MAAMxC,KAAK,CAACA;QACZ,MAAMuB,UAAUvB,iBAAiB6D,QAAQ7D,MAAMuB,OAAO,GAAGuC,OAAO9D;QAChE9D,WAAW,CAAC,kCAAkC,CAAC,EAAE;YAAC8D;QAAK;QACvDlC,OAAOkC,KAAK,CAAC,CAAC,oCAAoC,EAAEuB,SAAS,EAAE;YAACtB,MAAM;QAAC;IACzE;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/buildApp.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {\n AppBuildTrace,\n buildDebug,\n buildStaticFiles,\n formatModuleSizes,\n getAutoUpdatesCssUrls,\n getAutoUpdatesImportMap,\n resolveVendorBuildConfig,\n sortModulesBySize,\n} from '@sanity/cli-build/_internal/build'\nimport {getAppEnvironmentVariables} from '@sanity/cli-build/_internal/env'\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {getAppId} from '../../util/appId.js'\nimport {\n compareDependencyVersions,\n CompareDependencyVersionsResult,\n} from '../../util/compareDependencyVersions.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {type BuildOptions} from './types.js'\n\ninterface InternalBuildOptions {\n appId: string | undefined\n appTitle: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n entry: string | undefined\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n services: DefineAppInput['services']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n views: DefineAppInput['views']\n vite: UserViteConfig | undefined\n workDir: string\n}\n\n/**\n * Build the Sanity app.\n *\n * @internal\n */\nexport async function buildApp(options: BuildOptions): Promise<void> {\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const app = cliConfig && 'app' in cliConfig ? cliConfig.app : undefined\n // `views`/`services` live on the branded `unstable_defineApp` result, not the\n // legacy `app` config object — resolve the workbench capability to read them.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n await internalBuildApp({\n appId,\n appTitle: app?.title,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\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: 'app', output})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'app', output),\n entry: app?.entry,\n isWorkbenchApp: !!workbench,\n minify: flags.minify,\n outDir,\n output,\n reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n schemaExtraction: cliConfig?.schemaExtraction,\n services: workbench?.services,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: flags.yes,\n views: workbench?.views,\n vite: cliConfig.vite,\n workDir,\n })\n}\n\n/**\n * Internal build app that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nasync function internalBuildApp(options: InternalBuildOptions): Promise<void> {\n buildDebug(`Building app`)\n\n const {appId, determineBasePath, outDir, output, workDir} = options\n let {autoUpdatesEnabled} = options\n const unattendedMode = options.unattendedMode\n\n const timer = getTimer()\n\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n const installedSdkVersion = await getLocalPackageVersion('@sanity/sdk-react', workDir)\n const installedSanityVersion = await getLocalPackageVersion('sanity', workDir)\n\n if (!installedSdkVersion) {\n output.error(`Failed to find installed @sanity/sdk-react version`, {exit: 1})\n return\n }\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSDKVersion = semverParse(installedSdkVersion)?.version\n if (!cleanSDKVersion) {\n output.error(`Failed to parse installed SDK version: ${installedSdkVersion}`, {exit: 1})\n return\n }\n\n // Sanity might not be installed, but if it is, we want to auto update it.\n const cleanSanityVersion = semverParse(installedSanityVersion)?.version\n\n const autoUpdatedPackages = [\n {name: '@sanity/sdk', version: cleanSDKVersion},\n {name: '@sanity/sdk-react', version: cleanSDKVersion},\n ...(cleanSanityVersion\n ? [{cssFile: 'index.css', name: 'sanity' as const, version: cleanSanityVersion}]\n : []),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(autoUpdatedPackages, {appId})\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(autoUpdatedPackages, {appId})\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n // Warn if auto updates enabled but no appId configured.\n options.checkAppId()\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(autoUpdatedPackages)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\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 shouldContinue = await confirm({\n default: false,\n message: styleText('yellow', `${versionMismatchWarning} \\n\\nContinue anyway?`),\n })\n\n if (!shouldContinue) {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = Object.keys(getAppEnvironmentVariables())\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) output.log(`- ${key}`)\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 const basePath = determineBasePath()\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(`Building Sanity application`).start()\n\n const trace = getCliTelemetry().trace(AppBuildTrace)\n trace.start()\n\n let autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: true}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n appTitle: options.appTitle,\n autoUpdates,\n basePath,\n cwd: workDir,\n entry: options.entry,\n isApp: true,\n isWorkbenchApp: options.isWorkbenchApp,\n minify: options.minify,\n outputDir,\n reactCompiler: options.reactCompiler,\n schemaExtraction: options.schemaExtraction,\n services: options.services,\n sourceMap: options.sourceMap,\n views: options.views,\n vite: options.vite,\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 application (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n if (options.stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n\n trace.complete()\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 application`, {error})\n output.error(`Failed to build Sanity application: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","AppBuildTrace","buildDebug","buildStaticFiles","formatModuleSizes","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","resolveVendorBuildConfig","sortModulesBySize","getAppEnvironmentVariables","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","spinner","resolveWorkbenchApp","parse","semverParse","getAppId","compareDependencyVersions","warnAboutMissingAppId","determineBasePath","handlePrereleaseVersions","buildApp","options","cliConfig","flags","outDir","output","workDir","app","undefined","workbench","appId","internalBuildApp","appTitle","title","autoUpdatesEnabled","checkAppId","calledFromDeploy","appType","packages","entry","isWorkbenchApp","minify","reactCompiler","schemaExtraction","services","sourceMap","Boolean","stats","unattendedMode","yes","views","vite","timer","defaultOutputDir","resolve","join","outputDir","installedSdkVersion","installedSanityVersion","error","exit","autoUpdatesImports","autoUpdatesCssUrls","cleanSDKVersion","version","cleanSanityVersion","autoUpdatedPackages","name","cssFile","log","info","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","shouldContinue","default","message","warn","envVarKeys","Object","keys","key","shouldClean","basePath","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","cssUrls","imports","vendor","cwd","isApp","bundle","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","slice","complete","fail","Error","String"],"mappings":"AAAA,SAAQA,EAAE,QAAO,mBAAkB;AACnC,OAAOC,UAAU,YAAW;AAC5B,SAAQC,SAAS,QAAO,YAAW;AAEnC,SACEC,aAAa,EACbC,UAAU,EACVC,gBAAgB,EAChBC,iBAAiB,EACjBC,qBAAqB,EACrBC,uBAAuB,EACvBC,wBAAwB,EACxBC,iBAAiB,QACZ,oCAAmC;AAC1C,SAAQC,0BAA0B,QAAO,kCAAiC;AAC1E,SAEEC,eAAe,EACfC,sBAAsB,EACtBC,QAAQ,EACRC,aAAa,QAGR,mBAAkB;AACzB,SAAQC,OAAO,EAAEC,UAAU,EAAEC,OAAO,QAA6B,sBAAqB;AAEtF,SAAQC,mBAAmB,QAAO,8BAA6B;AAC/D,SAAQC,SAASC,WAAW,QAAO,SAAQ;AAE3C,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SACEC,yBAAyB,QAEpB,0CAAyC;AAChD,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,wBAAwB,QAAO,gCAA+B;AA4BtE;;;;CAIC,GACD,OAAO,eAAeC,SAASC,OAAqB;IAClD,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAEpD,MAAMM,MAAML,aAAa,SAASA,YAAYA,UAAUK,GAAG,GAAGC;IAC9D,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAMC,YAAYjB,oBAAoBU;IAEtC,MAAMQ,QAAQf,SAASO;IAEvB,MAAMS,iBAAiB;QACrBD;QACAE,UAAUL,KAAKM;QACfC,oBAAoBb,QAAQa,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACL,SAAS,CAACT,QAAQe,gBAAgB,EAAE;gBACvCnB,sBAAsB;oBAACoB,SAAS;oBAAOZ;gBAAM;YAC/C;QACF;QACAT,2BAA2B,CAACsB,WAAatB,0BAA0BsB,UAAUZ,SAAS;gBAACI;YAAK;QAC5FZ,mBAAmB,IAAMA,kBAAkBI,WAAW,OAAOG;QAC7Dc,OAAOZ,KAAKY;QACZC,gBAAgB,CAAC,CAACX;QAClBY,QAAQlB,MAAMkB,MAAM;QACpBjB;QACAC;QACAiB,eAAepB,aAAa,mBAAmBA,YAAYA,UAAUoB,aAAa,GAAGd;QACrFe,kBAAkBrB,WAAWqB;QAC7BC,UAAUf,WAAWe;QACrBC,WAAWC,QAAQvB,KAAK,CAAC,cAAc;QACvCwB,OAAOxB,MAAMwB,KAAK;QAClBC,gBAAgBzB,MAAM0B,GAAG;QACzBC,OAAOrB,WAAWqB;QAClBC,MAAM7B,UAAU6B,IAAI;QACpBzB;IACF;AACF;AAEA;;;CAGC,GACD,eAAeK,iBAAiBV,OAA6B;IAC3DxB,WAAW,CAAC,YAAY,CAAC;IAEzB,MAAM,EAACiC,KAAK,EAAEZ,iBAAiB,EAAEM,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAC5D,IAAI,EAACa,kBAAkB,EAAC,GAAGb;IAC3B,MAAM2B,iBAAiB3B,QAAQ2B,cAAc;IAE7C,MAAMI,QAAQ7C;IAEd,MAAM8C,mBAAmB3D,KAAK4D,OAAO,CAAC5D,KAAK6D,IAAI,CAAC7B,SAAS;IACzD,MAAM8B,YAAY9D,KAAK4D,OAAO,CAAC9B,UAAU6B;IAEzC,MAAMI,sBAAsB,MAAMnD,uBAAuB,qBAAqBoB;IAC9E,MAAMgC,yBAAyB,MAAMpD,uBAAuB,UAAUoB;IAEtE,IAAI,CAAC+B,qBAAqB;QACxBhC,OAAOkC,KAAK,CAAC,CAAC,kDAAkD,CAAC,EAAE;YAACC,MAAM;QAAC;QAC3E;IACF;IAEA,IAAIC,qBAAqB,CAAC;IAC1B,IAAIC,qBAA+B,EAAE;IAErC,IAAI5B,oBAAoB;QACtB,iFAAiF;QACjF,MAAM6B,kBAAkBjD,YAAY2C,sBAAsBO;QAC1D,IAAI,CAACD,iBAAiB;YACpBtC,OAAOkC,KAAK,CAAC,CAAC,uCAAuC,EAAEF,qBAAqB,EAAE;gBAACG,MAAM;YAAC;YACtF;QACF;QAEA,0EAA0E;QAC1E,MAAMK,qBAAqBnD,YAAY4C,yBAAyBM;QAEhE,MAAME,sBAAsB;YAC1B;gBAACC,MAAM;gBAAeH,SAASD;YAAe;YAC9C;gBAACI,MAAM;gBAAqBH,SAASD;YAAe;eAChDE,qBACA;gBAAC;oBAACG,SAAS;oBAAaD,MAAM;oBAAmBH,SAASC;gBAAkB;aAAE,GAC9E,EAAE;SACP;QACDJ,qBAAqB5D,wBAAwBiE,qBAAqB;YAACpC;QAAK;QACxEgC,qBAAqB9D,sBAAsBkE,qBAAqB;YAACpC;QAAK;QAEtEL,OAAO4C,GAAG,CAAC,GAAG3D,WAAW4D,IAAI,CAAC,mCAAmC,CAAC;QAElE,wDAAwD;QACxDjD,QAAQc,UAAU;QAElB,qBAAqB;QACrB,MAAM,EAACoC,UAAU,EAAEC,oBAAoB,EAAC,GACtC,MAAMnD,QAAQL,yBAAyB,CAACkD;QAE1C,IAAIM,qBAAqBC,MAAM,GAAG,GAAG;YACnC,MAAMtD,yBAAyB;gBAACM;gBAAQuB;gBAAgBwB;YAAoB;YAC5EX,qBAAqB,CAAC;YACtBC,qBAAqB,EAAE;YACvB5B,qBAAqB;QACvB;QAEA,IAAIqC,WAAWE,MAAM,GAAG,KAAKvC,oBAAoB;YAC/C,MAAMwC,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,EAAExB,IAAI,CAAC,OAAO;YAE5H,0EAA0E;YAC1E,IAAI/C,mBAAmB,CAACwC,gBAAgB;gBACtC,MAAMgC,iBAAiB,MAAMvE,QAAQ;oBACnCwE,SAAS;oBACTC,SAASvF,UAAU,UAAU,GAAG+E,uBAAuB,qBAAqB,CAAC;gBAC/E;gBAEA,IAAI,CAACM,gBAAgB;oBACnBvD,OAAOkC,KAAK,CAAC,mCAAmC;wBAACC,MAAM;oBAAC;oBACxD;gBACF;YACF,OAAO;gBACL,0DAA0D;gBAC1DnC,OAAO0D,IAAI,CAACT;YACd;QACF;IACF;IAEA,MAAMU,aAAaC,OAAOC,IAAI,CAAClF;IAC/B,IAAIgF,WAAWX,MAAM,GAAG,GAAG;QACzBhD,OAAO4C,GAAG,CAAC;QACX,KAAK,MAAMkB,OAAOH,WAAY3D,OAAO4C,GAAG,CAAC,CAAC,EAAE,EAAEkB,KAAK;QACnD9D,OAAO4C,GAAG,CAAC;IACb;IAEA,IAAImB,cAAc;IAClB,IAAIhC,cAAcH,oBAAoB,CAACL,kBAAkBxC,iBAAiB;QACxEgF,cAAc,MAAM/E,QAAQ;YAC1BwE,SAAS;YACTC,SAAS,CAAC,8CAA8C,EAAE1B,UAAU,QAAQ,CAAC;QAC/E;IACF;IAEA,MAAMiC,WAAWvE;IAEjB,IAAIwE;IACJ,IAAIF,aAAa;QACfpC,MAAMuC,KAAK,CAAC;QACZD,OAAO/E,QAAQ,uBAAuBgF,KAAK;QAC3C,MAAMlG,GAAG+D,WAAW;YAACoC,OAAO;YAAMC,WAAW;QAAI;QACjD,MAAMC,gBAAgB1C,MAAM2C,GAAG,CAAC;QAChCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEF,cAAcG,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;IACd;IAEAR,OAAO/E,QAAQ,CAAC,2BAA2B,CAAC,EAAEgF,KAAK;IAEnD,MAAMQ,QAAQ9F,kBAAkB8F,KAAK,CAACvG;IACtCuG,MAAMR,KAAK;IAEX,IAAIS;IACJ,IAAIlE,sBAAsB,CAACb,QAAQmB,cAAc,EAAE;QACjD4D,cAAc;YACZC,SAASvC;YACTwC,SAASzC;YACT0C,QAAQ,MAAMrG,yBAAyB;gBAACsG,KAAK9E;gBAAS+E,OAAO;YAAI;QACnE;IACF;IAEA,IAAI;QACFrD,MAAMuC,KAAK,CAAC;QAEZ,MAAMe,SAAS,MAAM5G,iBAAiB;YACpCkC,UAAUX,QAAQW,QAAQ;YAC1BoE;YACAX;YACAe,KAAK9E;YACLa,OAAOlB,QAAQkB,KAAK;YACpBkE,OAAO;YACPjE,gBAAgBnB,QAAQmB,cAAc;YACtCC,QAAQpB,QAAQoB,MAAM;YACtBe;YACAd,eAAerB,QAAQqB,aAAa;YACpCC,kBAAkBtB,QAAQsB,gBAAgB;YAC1CC,UAAUvB,QAAQuB,QAAQ;YAC1BC,WAAWxB,QAAQwB,SAAS;YAC5BK,OAAO7B,QAAQ6B,KAAK;YACpBC,MAAM9B,QAAQ8B,IAAI;QACpB;QAEAgD,MAAM9B,GAAG,CAAC;YACRsC,YAAYD,OAAOE,MAAM,CACtBC,OAAO,CAAC,CAACC,QAAUA,MAAMC,OAAO,CAACF,OAAO,CAAC,CAACjC,MAAQA,IAAIoC,cAAc,GACpEC,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,GAAG;QACjC;QACA,MAAMC,gBAAgBhE,MAAM2C,GAAG,CAAC;QAEhCL,KAAKM,IAAI,GAAG,CAAC,0BAA0B,EAAEoB,cAAcnB,OAAO,CAAC,GAAG,GAAG,CAAC;QACtEP,KAAKQ,OAAO;QAEZ,IAAI7E,QAAQ0B,KAAK,EAAE;YACjBtB,OAAO4C,GAAG,CAAC;YACX5C,OAAO4C,GAAG,CAACtE,kBAAkBI,kBAAkBuG,OAAOE,MAAM,EAAES,KAAK,CAAC,GAAG;QACzE;QAEAlB,MAAMmB,QAAQ;IAChB,EAAE,OAAO3D,OAAO;QACd+B,KAAK6B,IAAI;QACTpB,MAAMxC,KAAK,CAACA;QACZ,MAAMuB,UAAUvB,iBAAiB6D,QAAQ7D,MAAMuB,OAAO,GAAGuC,OAAO9D;QAChE9D,WAAW,CAAC,kCAAkC,CAAC,EAAE;YAAC8D;QAAK;QACvDlC,OAAOkC,KAAK,CAAC,CAAC,oCAAoC,EAAEuB,SAAS,EAAE;YAACtB,MAAM;QAAC;IACzE;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { rm } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
|
-
import { buildDebug, checkRequiredDependencies, checkStudioDependencyVersions, getAutoUpdatesCssUrls, getAutoUpdatesImportMap, resolveVendorBuildConfig, StudioBuildTrace } from '@sanity/cli-build/_internal/build';
|
|
4
|
+
import { buildDebug, buildStaticFiles, checkRequiredDependencies, checkStudioDependencyVersions, formatModuleSizes, getAutoUpdatesCssUrls, getAutoUpdatesImportMap, resolveVendorBuildConfig, sortModulesBySize, StudioBuildTrace } from '@sanity/cli-build/_internal/build';
|
|
5
5
|
import { getStudioEnvironmentVariables } from '@sanity/cli-build/_internal/env';
|
|
6
6
|
import { getCliTelemetry, getLocalPackageVersion, getTimer, isInteractive } from '@sanity/cli-core';
|
|
7
7
|
import { confirm, logSymbols, select, spinner } from '@sanity/cli-core/ux';
|
|
@@ -10,11 +10,9 @@ import { parse as semverParse } from 'semver';
|
|
|
10
10
|
import { getAppId } from '../../util/appId.js';
|
|
11
11
|
import { compareDependencyVersions } from '../../util/compareDependencyVersions.js';
|
|
12
12
|
import { determineIsApp } from '../../util/determineIsApp.js';
|
|
13
|
-
import { formatModuleSizes, sortModulesBySize } from '../../util/moduleFormatUtils.js';
|
|
14
13
|
import { getPackageManagerChoice } from '../../util/packageManager/packageManagerChoice.js';
|
|
15
14
|
import { upgradePackages } from '../../util/packageManager/upgradePackages.js';
|
|
16
15
|
import { warnAboutMissingAppId } from '../../util/warnAboutMissingAppId.js';
|
|
17
|
-
import { buildStaticFiles } from './buildStaticFiles.js';
|
|
18
16
|
import { determineBasePath } from './determineBasePath.js';
|
|
19
17
|
import { handlePrereleaseVersions } from './handlePrereleaseVersions.js';
|
|
20
18
|
/**
|
|
@@ -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 {\n buildDebug,\n checkRequiredDependencies,\n checkStudioDependencyVersions,\n getAutoUpdatesCssUrls,\n getAutoUpdatesImportMap,\n resolveVendorBuildConfig,\n StudioBuildTrace,\n} from '@sanity/cli-build/_internal/build'\nimport {getStudioEnvironmentVariables} from '@sanity/cli-build/_internal/env'\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, select, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {getAppId} from '../../util/appId.js'\nimport {\n compareDependencyVersions,\n CompareDependencyVersionsResult,\n} from '../../util/compareDependencyVersions.js'\nimport {determineIsApp} from '../../util/determineIsApp.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 {buildStaticFiles} from './buildStaticFiles.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {type BuildOptions} from './types.js'\n\ninterface InternalBuildOptions {\n appId: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n isApp: boolean\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n services: DefineAppInput['services']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n upgradePackages(options: {packages: [name: string, version: string][]}): Promise<void>\n views: DefineAppInput['views']\n vite: UserViteConfig | undefined\n workDir: string\n}\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const {calledFromDeploy, cliConfig, flags, outDir, output, workDir} = options\n\n // `views`/`services` live on the branded `unstable_defineApp` result — resolve\n // the workbench capability so it's gated on the brand, like the app build.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n const upgradePkgs = async (options: {\n packages: [name: string, version: string][]\n }): Promise<void> => {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: options.packages,\n },\n {output, workDir},\n )\n }\n\n await internalBuildStudio({\n appId,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\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 && !calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId: cliConfig?.api?.projectId})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'studio', output),\n isApp: determineIsApp(cliConfig),\n isWorkbenchApp: !!workbench,\n minify: Boolean(flags.minify),\n outDir,\n output,\n reactCompiler: cliConfig.reactCompiler,\n schemaExtraction: cliConfig.schemaExtraction,\n services: workbench?.services,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: Boolean(flags.yes),\n upgradePackages: upgradePkgs,\n views: workbench?.views,\n vite: cliConfig.vite,\n workDir,\n })\n}\n\n/**\n * Internal build studio that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nasync function internalBuildStudio(options: InternalBuildOptions): Promise<void> {\n buildDebug(`Building studio`)\n\n const timer = getTimer()\n const {\n appId,\n determineBasePath,\n isApp,\n minify,\n outDir,\n output,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap,\n stats,\n unattendedMode,\n upgradePackages,\n views,\n vite,\n workDir,\n } = options\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 isApp,\n output,\n workDir,\n })\n\n let autoUpdatesEnabled = options.autoUpdatesEnabled\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSanityVersion = semverParse(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 // Warn if auto updates enabled but no appId configured\n options.checkAppId()\n\n const installedVisionVersion = await getLocalPackageVersion('@sanity/vision', workDir)\n const cleanVisionVersion = installedVisionVersion\n ? semverParse(installedVisionVersion)?.version\n : undefined\n\n const sanityDependencies = [\n {cssFile: 'index.css', name: 'sanity', version: cleanSanityVersion},\n ...(cleanVisionVersion\n ? [{cssFile: 'index.css', name: '@sanity/vision' as const, version: cleanVisionVersion}]\n : [{name: '@sanity/vision' as const, version: cleanSanityVersion}]),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {appId})\n\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(sanityDependencies, {appId})\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(sanityDependencies)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\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 packages: mismatched.map((res) => [res.pkg, res.remote]),\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 = Object.keys(getStudioEnvironmentVariables())\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()\n\n if (schemaExtraction?.enabled) {\n output.log(`${logSymbols.info} Building with schema extraction enabled`)\n }\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 autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: false}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n autoUpdates,\n basePath,\n cwd: workDir,\n isWorkbenchApp: options.isWorkbenchApp,\n minify,\n outputDir,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap,\n views,\n vite,\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 (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","buildDebug","checkRequiredDependencies","checkStudioDependencyVersions","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","resolveVendorBuildConfig","StudioBuildTrace","getStudioEnvironmentVariables","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","select","spinner","resolveWorkbenchApp","parse","semverParse","getAppId","compareDependencyVersions","determineIsApp","formatModuleSizes","sortModulesBySize","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","buildStaticFiles","determineBasePath","handlePrereleaseVersions","buildStudio","options","calledFromDeploy","cliConfig","flags","outDir","output","workDir","workbench","appId","upgradePkgs","packageManager","interactive","chosen","packages","internalBuildStudio","autoUpdatesEnabled","checkAppId","appType","projectId","api","isApp","isWorkbenchApp","minify","Boolean","reactCompiler","schemaExtraction","services","sourceMap","stats","unattendedMode","yes","views","vite","timer","defaultOutputDir","resolve","join","outputDir","installedSanityVersion","autoUpdatesImports","autoUpdatesCssUrls","cleanSanityVersion","version","Error","log","info","installedVisionVersion","cleanVisionVersion","undefined","sanityDependencies","cssFile","name","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","choice","choices","value","default","message","warning","error","exit","res","warn","envVarKeys","Object","keys","key","shouldClean","basePath","enabled","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","cssUrls","imports","vendor","cwd","bundle","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","complete","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 {\n buildDebug,\n buildStaticFiles,\n checkRequiredDependencies,\n checkStudioDependencyVersions,\n formatModuleSizes,\n getAutoUpdatesCssUrls,\n getAutoUpdatesImportMap,\n resolveVendorBuildConfig,\n sortModulesBySize,\n StudioBuildTrace,\n} from '@sanity/cli-build/_internal/build'\nimport {getStudioEnvironmentVariables} from '@sanity/cli-build/_internal/env'\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, select, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {getAppId} from '../../util/appId.js'\nimport {\n compareDependencyVersions,\n CompareDependencyVersionsResult,\n} from '../../util/compareDependencyVersions.js'\nimport {determineIsApp} from '../../util/determineIsApp.js'\nimport {getPackageManagerChoice} from '../../util/packageManager/packageManagerChoice.js'\nimport {upgradePackages} from '../../util/packageManager/upgradePackages.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {type BuildOptions} from './types.js'\n\ninterface InternalBuildOptions {\n appId: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n isApp: boolean\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n services: DefineAppInput['services']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n upgradePackages(options: {packages: [name: string, version: string][]}): Promise<void>\n views: DefineAppInput['views']\n vite: UserViteConfig | undefined\n workDir: string\n}\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const {calledFromDeploy, cliConfig, flags, outDir, output, workDir} = options\n\n // `views`/`services` live on the branded `unstable_defineApp` result — resolve\n // the workbench capability so it's gated on the brand, like the app build.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n const upgradePkgs = async (options: {\n packages: [name: string, version: string][]\n }): Promise<void> => {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: options.packages,\n },\n {output, workDir},\n )\n }\n\n await internalBuildStudio({\n appId,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\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 && !calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId: cliConfig?.api?.projectId})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'studio', output),\n isApp: determineIsApp(cliConfig),\n isWorkbenchApp: !!workbench,\n minify: Boolean(flags.minify),\n outDir,\n output,\n reactCompiler: cliConfig.reactCompiler,\n schemaExtraction: cliConfig.schemaExtraction,\n services: workbench?.services,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: Boolean(flags.yes),\n upgradePackages: upgradePkgs,\n views: workbench?.views,\n vite: cliConfig.vite,\n workDir,\n })\n}\n\n/**\n * Internal build studio that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nasync function internalBuildStudio(options: InternalBuildOptions): Promise<void> {\n buildDebug(`Building studio`)\n\n const timer = getTimer()\n const {\n appId,\n determineBasePath,\n isApp,\n minify,\n outDir,\n output,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap,\n stats,\n unattendedMode,\n upgradePackages,\n views,\n vite,\n workDir,\n } = options\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 isApp,\n output,\n workDir,\n })\n\n let autoUpdatesEnabled = options.autoUpdatesEnabled\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSanityVersion = semverParse(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 // Warn if auto updates enabled but no appId configured\n options.checkAppId()\n\n const installedVisionVersion = await getLocalPackageVersion('@sanity/vision', workDir)\n const cleanVisionVersion = installedVisionVersion\n ? semverParse(installedVisionVersion)?.version\n : undefined\n\n const sanityDependencies = [\n {cssFile: 'index.css', name: 'sanity', version: cleanSanityVersion},\n ...(cleanVisionVersion\n ? [{cssFile: 'index.css', name: '@sanity/vision' as const, version: cleanVisionVersion}]\n : [{name: '@sanity/vision' as const, version: cleanSanityVersion}]),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {appId})\n\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(sanityDependencies, {appId})\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(sanityDependencies)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\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 packages: mismatched.map((res) => [res.pkg, res.remote]),\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 = Object.keys(getStudioEnvironmentVariables())\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()\n\n if (schemaExtraction?.enabled) {\n output.log(`${logSymbols.info} Building with schema extraction enabled`)\n }\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 autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: false}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n autoUpdates,\n basePath,\n cwd: workDir,\n isWorkbenchApp: options.isWorkbenchApp,\n minify,\n outputDir,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap,\n views,\n vite,\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 (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","buildDebug","buildStaticFiles","checkRequiredDependencies","checkStudioDependencyVersions","formatModuleSizes","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","resolveVendorBuildConfig","sortModulesBySize","StudioBuildTrace","getStudioEnvironmentVariables","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","select","spinner","resolveWorkbenchApp","parse","semverParse","getAppId","compareDependencyVersions","determineIsApp","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","determineBasePath","handlePrereleaseVersions","buildStudio","options","calledFromDeploy","cliConfig","flags","outDir","output","workDir","workbench","appId","upgradePkgs","packageManager","interactive","chosen","packages","internalBuildStudio","autoUpdatesEnabled","checkAppId","appType","projectId","api","isApp","isWorkbenchApp","minify","Boolean","reactCompiler","schemaExtraction","services","sourceMap","stats","unattendedMode","yes","views","vite","timer","defaultOutputDir","resolve","join","outputDir","installedSanityVersion","autoUpdatesImports","autoUpdatesCssUrls","cleanSanityVersion","version","Error","log","info","installedVisionVersion","cleanVisionVersion","undefined","sanityDependencies","cssFile","name","mismatched","unresolvedPrerelease","length","versionMismatchWarning","map","mod","pkg","installed","remote","choice","choices","value","default","message","warning","error","exit","res","warn","envVarKeys","Object","keys","key","shouldClean","basePath","enabled","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","cssUrls","imports","vendor","cwd","bundle","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","complete","slice","fail","String"],"mappings":"AAAA,SAAQA,EAAE,QAAO,mBAAkB;AACnC,OAAOC,UAAU,YAAW;AAC5B,SAAQC,SAAS,QAAO,YAAW;AAEnC,SACEC,UAAU,EACVC,gBAAgB,EAChBC,yBAAyB,EACzBC,6BAA6B,EAC7BC,iBAAiB,EACjBC,qBAAqB,EACrBC,uBAAuB,EACvBC,wBAAwB,EACxBC,iBAAiB,EACjBC,gBAAgB,QACX,oCAAmC;AAC1C,SAAQC,6BAA6B,QAAO,kCAAiC;AAC7E,SAEEC,eAAe,EACfC,sBAAsB,EACtBC,QAAQ,EACRC,aAAa,QAGR,mBAAkB;AACzB,SAAQC,OAAO,EAAEC,UAAU,EAAEC,MAAM,EAAEC,OAAO,QAA6B,sBAAqB;AAE9F,SAAQC,mBAAmB,QAAO,8BAA6B;AAC/D,SAAQC,SAASC,WAAW,QAAO,SAAQ;AAE3C,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SACEC,yBAAyB,QAEpB,0CAAyC;AAChD,SAAQC,cAAc,QAAO,+BAA8B;AAC3D,SAAQC,uBAAuB,QAAO,oDAAmD;AACzF,SAAQC,eAAe,QAAO,+CAA8C;AAC5E,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,wBAAwB,QAAO,gCAA+B;AA4BtE;;;;CAIC,GACD,OAAO,eAAeC,YAAYC,OAAqB;IACrD,MAAM,EAACC,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGN;IAEtE,+EAA+E;IAC/E,2EAA2E;IAC3E,MAAMO,YAAYnB,oBAAoBc;IAEtC,MAAMM,QAAQjB,SAASW;IAEvB,MAAMO,cAAc,OAAOT;QAGzB,MAAML,gBACJ;YACEe,gBAAgB,AAAC,CAAA,MAAMhB,wBAAwBY,SAAS;gBAACK,aAAa;YAAK,EAAC,EAAGC,MAAM;YACrFC,UAAUb,QAAQa,QAAQ;QAC5B,GACA;YAACR;YAAQC;QAAO;IAEpB;IAEA,MAAMQ,oBAAoB;QACxBN;QACAO,oBAAoBf,QAAQe,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACR,SAAS,CAACP,kBAAkB;gBAC/BL,sBAAsB;oBAACqB,SAAS;oBAAUZ;oBAAQa,WAAWhB,WAAWiB,KAAKD;gBAAS;YACxF;QACF;QACA1B,2BAA2B,CAACqB,WAAarB,0BAA0BqB,UAAUP,SAAS;gBAACE;YAAK;QAC5FX,mBAAmB,IAAMA,kBAAkBK,WAAW,UAAUG;QAChEe,OAAO3B,eAAeS;QACtBmB,gBAAgB,CAAC,CAACd;QAClBe,QAAQC,QAAQpB,MAAMmB,MAAM;QAC5BlB;QACAC;QACAmB,eAAetB,UAAUsB,aAAa;QACtCC,kBAAkBvB,UAAUuB,gBAAgB;QAC5CC,UAAUnB,WAAWmB;QACrBC,WAAWJ,QAAQpB,KAAK,CAAC,cAAc;QACvCyB,OAAOzB,MAAMyB,KAAK;QAClBC,gBAAgBN,QAAQpB,MAAM2B,GAAG;QACjCnC,iBAAiBc;QACjBsB,OAAOxB,WAAWwB;QAClBC,MAAM9B,UAAU8B,IAAI;QACpB1B;IACF;AACF;AAEA;;;CAGC,GACD,eAAeQ,oBAAoBd,OAA6B;IAC9D/B,WAAW,CAAC,eAAe,CAAC;IAE5B,MAAMgE,QAAQnD;IACd,MAAM,EACJ0B,KAAK,EACLX,iBAAiB,EACjBuB,KAAK,EACLE,MAAM,EACNlB,MAAM,EACNC,MAAM,EACNmB,aAAa,EACbC,gBAAgB,EAChBC,QAAQ,EACRC,SAAS,EACTC,KAAK,EACLC,cAAc,EACdlC,eAAe,EACfoC,KAAK,EACLC,IAAI,EACJ1B,OAAO,EACR,GAAGN;IACJ,MAAMkC,mBAAmBnE,KAAKoE,OAAO,CAACpE,KAAKqE,IAAI,CAAC9B,SAAS;IACzD,MAAM+B,YAAYtE,KAAKoE,OAAO,CAAC/B,UAAU8B;IAEzC,MAAM9D,8BAA8BkC,SAASD;IAE7C,iFAAiF;IACjF,6BAA6B;IAC7B,MAAM,EAACiC,sBAAsB,EAAC,GAAG,MAAMnE,0BAA0B;QAC/DiD;QACAf;QACAC;IACF;IAEA,IAAIS,qBAAqBf,QAAQe,kBAAkB;IAEnD,IAAIwB,qBAAqB,CAAC;IAC1B,IAAIC,qBAA+B,EAAE;IAErC,IAAIzB,oBAAoB;QACtB,iFAAiF;QACjF,MAAM0B,qBAAqBnD,YAAYgD,yBAAyBI;QAChE,IAAI,CAACD,oBAAoB;YACvB,MAAM,IAAIE,MAAM,CAAC,0CAA0C,EAAEL,wBAAwB;QACvF;QAEAjC,OAAOuC,GAAG,CAAC,GAAG3D,WAAW4D,IAAI,CAAC,mCAAmC,CAAC;QAElE,uDAAuD;QACvD7C,QAAQgB,UAAU;QAElB,MAAM8B,yBAAyB,MAAMjE,uBAAuB,kBAAkByB;QAC9E,MAAMyC,qBAAqBD,yBACvBxD,YAAYwD,yBAAyBJ,UACrCM;QAEJ,MAAMC,qBAAqB;YACzB;gBAACC,SAAS;gBAAaC,MAAM;gBAAUT,SAASD;YAAkB;eAC9DM,qBACA;gBAAC;oBAACG,SAAS;oBAAaC,MAAM;oBAA2BT,SAASK;gBAAkB;aAAE,GACtF;gBAAC;oBAACI,MAAM;oBAA2BT,SAASD;gBAAkB;aAAE;SACrE;QACDF,qBAAqBhE,wBAAwB0E,oBAAoB;YAACzC;QAAK;QAEvEgC,qBAAqBlE,sBAAsB2E,oBAAoB;YAACzC;QAAK;QAErE,qBAAqB;QACrB,MAAM,EAAC4C,UAAU,EAAEC,oBAAoB,EAAC,GACtC,MAAMrD,QAAQR,yBAAyB,CAACyD;QAE1C,IAAII,qBAAqBC,MAAM,GAAG,GAAG;YACnC,MAAMxD,yBAAyB;gBAACO;gBAAQwB;gBAAgBwB;YAAoB;YAC5Ed,qBAAqB,CAAC;YACtBC,qBAAqB,EAAE;YACvBzB,qBAAqB;QACvB;QAEA,IAAIqC,WAAWE,MAAM,GAAG,KAAKvC,oBAAoB;YAC/C,MAAMwC,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,EAAExB,IAAI,CAAC,OAAO;YAE5H,0EAA0E;YAC1E,IAAIrD,mBAAmB,CAAC8C,gBAAgB;gBACtC,MAAMgC,SAAS,MAAM3E,OAAO;oBAC1B4E,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,SAASjG,UACP,UACA,GAAGiB,WAAWiF,OAAO,CAAC,CAAC,EAAEX,uBAAuB,2DAA2D,CAAC;gBAEhH;gBAEA,IAAIM,WAAW,UAAU;oBACvBxD,OAAO8D,KAAK,CAAC,mCAAmC;wBAACC,MAAM;oBAAC;oBACxD;gBACF;gBAEA,IAAIP,WAAW,aAAaA,WAAW,uBAAuB;oBAC5D,MAAMlE,gBAAgB;wBACpBkB,UAAUuC,WAAWI,GAAG,CAAC,CAACa,MAAQ;gCAACA,IAAIX,GAAG;gCAAEW,IAAIT,MAAM;6BAAC;oBACzD;oBAEA,IAAIC,WAAW,WAAW;wBACxB;oBACF;gBACF;YACF,OAAO;gBACL,0DAA0D;gBAC1DxD,OAAOiE,IAAI,CAACf;YACd;QACF;IACF;IAEA,MAAMgB,aAAaC,OAAOC,IAAI,CAAC9F;IAC/B,IAAI4F,WAAWjB,MAAM,GAAG,GAAG;QACzBjD,OAAOuC,GAAG,CAAC;QACX,KAAK,MAAM8B,OAAOH,WAAY;YAC5BlE,OAAOuC,GAAG,CAAC,CAAC,EAAE,EAAE8B,KAAK;QACvB;QACArE,OAAOuC,GAAG,CAAC;IACb;IAEA,IAAI+B,cAAc;IAClB,IAAItC,cAAcH,oBAAoB,CAACL,kBAAkB9C,iBAAiB;QACxE4F,cAAc,MAAM3F,QAAQ;YAC1BgF,SAAS;YACTC,SAAS,CAAC,8CAA8C,EAAE5B,UAAU,QAAQ,CAAC;QAC/E;IACF;IAEA,uCAAuC;IACvC,MAAMuC,WAAW/E;IAEjB,IAAI4B,kBAAkBoD,SAAS;QAC7BxE,OAAOuC,GAAG,CAAC,GAAG3D,WAAW4D,IAAI,CAAC,wCAAwC,CAAC;IACzE;IAEA,IAAIiC;IACJ,IAAIH,aAAa;QACf1C,MAAM8C,KAAK,CAAC;QACZD,OAAO3F,QAAQ,uBAAuB4F,KAAK;QAC3C,MAAMjH,GAAGuE,WAAW;YAAC2C,OAAO;YAAMC,WAAW;QAAI;QACjD,MAAMC,gBAAgBjD,MAAMkD,GAAG,CAAC;QAChCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEF,cAAcG,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;IACd;IAEAR,OAAO3F,QAAQ,CAAC,mBAAmB,CAAC,EAAE4F,KAAK;IAE3C,MAAMQ,QAAQ3G,kBAAkB2G,KAAK,CAAC7G;IACtC6G,MAAMR,KAAK;IAEX,IAAIS;IACJ,IAAIzE,sBAAsB,CAACf,QAAQqB,cAAc,EAAE;QACjDmE,cAAc;YACZC,SAASjD;YACTkD,SAASnD;YACToD,QAAQ,MAAMnH,yBAAyB;gBAACoH,KAAKtF;gBAASc,OAAO;YAAK;QACpE;IACF;IAEA,IAAI;QACFa,MAAM8C,KAAK,CAAC;QAEZ,MAAMc,SAAS,MAAM3H,iBAAiB;YACpCsH;YACAZ;YACAgB,KAAKtF;YACLe,gBAAgBrB,QAAQqB,cAAc;YACtCC;YACAe;YACAb;YACAC;YACAC;YACAC;YACAI;YACAC;QACF;QAEAuD,MAAM3C,GAAG,CAAC;YACRkD,YAAYD,OAAOE,MAAM,CACtBC,OAAO,CAAC,CAACC,QAAUA,MAAMC,OAAO,CAACF,OAAO,CAAC,CAACvC,MAAQA,IAAI0C,cAAc,GACpEC,MAAM,CAAC,CAACC,KAAKC,IAAMD,MAAMC,GAAG;QACjC;QACA,MAAMC,gBAAgBtE,MAAMkD,GAAG,CAAC;QAEhCL,KAAKM,IAAI,GAAG,CAAC,qBAAqB,EAAEmB,cAAclB,OAAO,CAAC,GAAG,GAAG,CAAC;QACjEP,KAAKQ,OAAO;QAEZC,MAAMiB,QAAQ;QACd,IAAI5E,OAAO;YACTvB,OAAOuC,GAAG,CAAC;YACXvC,OAAOuC,GAAG,CAACvE,kBAAkBI,kBAAkBoH,OAAOE,MAAM,EAAEU,KAAK,CAAC,GAAG;QACzE;IACF,EAAE,OAAOtC,OAAO;QACdW,KAAK4B,IAAI;QACTnB,MAAMpB,KAAK,CAACA;QACZ,MAAMF,UAAUE,iBAAiBxB,QAAQwB,MAAMF,OAAO,GAAG0C,OAAOxC;QAChElG,WAAW,CAAC,6BAA6B,CAAC,EAAE;YAACkG;QAAK;QAClD9D,OAAO8D,KAAK,CAAC,CAAC,+BAA+B,EAAEF,SAAS,EAAE;YAACG,MAAM;QAAC;IACpE;AACF"}
|
|
@@ -212,20 +212,23 @@ function buildGitHubCopilotCliServerConfig(token) {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
function buildOpenCodeServerConfig(token) {
|
|
215
|
-
|
|
216
|
-
headers: {
|
|
217
|
-
Authorization: `Bearer ${token}`
|
|
218
|
-
},
|
|
215
|
+
const config = {
|
|
219
216
|
type: 'remote',
|
|
220
217
|
url: MCP_SERVER_URL
|
|
221
218
|
};
|
|
219
|
+
if (token) {
|
|
220
|
+
config.headers = {
|
|
221
|
+
Authorization: `Bearer ${token}`
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return config;
|
|
222
225
|
}
|
|
223
226
|
function buildZedServerConfig(token) {
|
|
224
227
|
return {
|
|
228
|
+
enabled: true,
|
|
225
229
|
headers: {
|
|
226
230
|
Authorization: `Bearer ${token}`
|
|
227
231
|
},
|
|
228
|
-
settings: {},
|
|
229
232
|
url: MCP_SERVER_URL
|
|
230
233
|
};
|
|
231
234
|
}
|
|
@@ -317,6 +320,7 @@ function buildZedServerConfig(token) {
|
|
|
317
320
|
buildServerConfig: buildOpenCodeServerConfig,
|
|
318
321
|
configKey: 'mcp',
|
|
319
322
|
detect: detectOpenCode,
|
|
323
|
+
oauthOnly: true,
|
|
320
324
|
skillsCliAgent: 'opencode'
|
|
321
325
|
},
|
|
322
326
|
// Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
|
|
@@ -327,6 +331,7 @@ function buildZedServerConfig(token) {
|
|
|
327
331
|
...EDITOR_DEFAULTS,
|
|
328
332
|
configKey: 'servers',
|
|
329
333
|
detect: detectVSCode,
|
|
334
|
+
oauthOnly: true,
|
|
330
335
|
skillsCliAgent: 'github-copilot'
|
|
331
336
|
},
|
|
332
337
|
// Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
|
|
@@ -335,6 +340,7 @@ function buildZedServerConfig(token) {
|
|
|
335
340
|
...EDITOR_DEFAULTS,
|
|
336
341
|
configKey: 'servers',
|
|
337
342
|
detect: detectVSCodeInsiders,
|
|
343
|
+
oauthOnly: true,
|
|
338
344
|
skillsCliAgent: 'github-copilot'
|
|
339
345
|
},
|
|
340
346
|
// Doc: https://zed.dev/docs/assistant/model-context-protocol
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/mcp/editorConfigs.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport {execa} from 'execa'\n\nimport {MCP_SERVER_URL} from '../../services/mcp.js'\n\n/**\n * Environment abstraction for editor detection.\n *\n * Detect functions receive this instead of using module-level imports, making\n * each function independently testable without global mocks.\n */\nexport interface DetectionEnv {\n env: Record<string, string | undefined>\n /** Run a CLI command to check if a tool is installed. Rejects on failure. */\n execCommand: (cmd: string, args: string[]) => Promise<void>\n existsSync: (p: string) => boolean\n homedir: string\n platform: NodeJS.Platform\n}\n\n/** Create the real detection environment backed by process/OS globals. */\nexport function createDetectionEnv(): DetectionEnv {\n return {\n env: process.env,\n execCommand: (cmd, args) => execa(cmd, args, {stdio: 'pipe', timeout: 5000}).then(() => {}),\n existsSync,\n homedir: os.homedir(),\n platform: process.platform,\n }\n}\n\ninterface EditorConfig {\n /** Builds the server config with API token. If oauthOnly is true, the token is not used */\n buildServerConfig: (token: string) => Record<string, unknown>\n configKey: string\n /** Returns the config file path if editor is detected, null otherwise */\n detect: (env: DetectionEnv) => Promise<string | null>\n format: 'jsonc' | 'toml'\n /** Extracts the auth token from a parsed Sanity server config block */\n readToken: (serverConfig: Record<string, unknown>) => string | undefined\n\n /** If true, this editor uses OAuth natively and does not need an embedded API token */\n oauthOnly?: boolean\n /**\n * Corresponding `--agent` value for the `skills` CLI (https://github.com/vercel-labs/skills).\n * Omit when the editor has no skills CLI equivalent.\n */\n skillsCliAgent?: string\n /**\n * The directory to install skills to.\n */\n skillsDir?: string\n}\n\n/**\n * The Sanity MCP server uses OAuth by default\n * If a token is provided, the server will not use OAuth instead tool calls will use the API token\n */\nconst defaultHttpConfig = (token?: string) => {\n const defaultConfig: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n defaultConfig.headers = {Authorization: `Bearer ${token}`}\n }\n\n return defaultConfig\n}\n\n// -- Detect functions --\n\nasync function detectClaudeCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('claude', ['--version'])\n return path.join(ctx.homedir, '.claude.json')\n } catch {\n return null\n }\n}\n\nasync function detectAntigravity(ctx: DetectionEnv): Promise<string | null> {\n const antigravityDir = path.join(ctx.homedir, '.gemini/antigravity')\n return ctx.existsSync(antigravityDir) ? path.join(antigravityDir, 'mcp_config.json') : null\n}\n\nexport function getVSCodeUserDir(\n ctx: DetectionEnv,\n variant: 'insiders' | 'stable' = 'stable',\n): string | null {\n switch (ctx.platform) {\n case 'darwin': {\n return path.join(\n ctx.homedir,\n variant === 'insiders'\n ? 'Library/Application Support/Code - Insiders/User'\n : 'Library/Application Support/Code/User',\n )\n }\n case 'win32': {\n if (!ctx.env.APPDATA) return null\n return path.join(\n ctx.env.APPDATA,\n variant === 'insiders' ? 'Code - Insiders/User' : 'Code/User',\n )\n }\n default: {\n return path.join(\n ctx.homedir,\n variant === 'insiders' ? '.config/Code - Insiders/User' : '.config/Code/User',\n )\n }\n }\n}\n\nasync function detectCline(ctx: DetectionEnv): Promise<string | null> {\n const vscodeUserDir = getVSCodeUserDir(ctx)\n if (!vscodeUserDir) return null\n const clineConfigDir = path.join(vscodeUserDir, 'globalStorage/saoudrizwan.claude-dev/settings')\n return ctx.existsSync(clineConfigDir)\n ? path.join(clineConfigDir, 'cline_mcp_settings.json')\n : null\n}\n\nasync function detectClineCli(ctx: DetectionEnv): Promise<string | null> {\n const clineHome = ctx.env.CLINE_DIR || path.join(ctx.homedir, '.cline')\n if (!ctx.existsSync(clineHome)) return null\n return path.join(clineHome, 'data/settings/cline_mcp_settings.json')\n}\n\nasync function detectCodexCli(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('codex', ['--version'])\n const codexHome = ctx.env.CODEX_HOME || path.join(ctx.homedir, '.codex')\n return path.join(codexHome, 'config.toml')\n } catch {\n return null\n }\n}\n\nasync function detectCursor(ctx: DetectionEnv): Promise<string | null> {\n const cursorDir = path.join(ctx.homedir, '.cursor')\n return ctx.existsSync(cursorDir) ? path.join(cursorDir, 'mcp.json') : null\n}\n\nasync function detectGeminiCli(ctx: DetectionEnv): Promise<string | null> {\n // Antigravity stores its config under ~/.gemini/antigravity, so checking\n // only the parent ~/.gemini directory causes false Gemini CLI detection.\n const settingsPath = path.join(ctx.homedir, '.gemini/settings.json')\n return ctx.existsSync(settingsPath) ? settingsPath : null\n}\n\nasync function detectGitHubCopilotCli(ctx: DetectionEnv): Promise<string | null> {\n const copilotDir =\n ctx.platform === 'linux' && ctx.env.XDG_CONFIG_HOME\n ? path.join(ctx.env.XDG_CONFIG_HOME, 'copilot')\n : path.join(ctx.homedir, '.copilot')\n return ctx.existsSync(copilotDir) ? path.join(copilotDir, 'mcp-config.json') : null\n}\n\nasync function detectOpenCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('opencode', ['--version'])\n return path.join(ctx.homedir, '.config/opencode/opencode.json')\n } catch {\n return null\n }\n}\n\nasync function detectVSCode(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx)\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectVSCodeInsiders(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx, 'insiders')\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectZed(ctx: DetectionEnv): Promise<string | null> {\n let configDir: string | null = null\n switch (ctx.platform) {\n case 'win32': {\n if (ctx.env.APPDATA) {\n configDir = path.join(ctx.env.APPDATA, 'Zed')\n }\n break\n }\n default: {\n configDir = path.join(ctx.homedir, '.config/zed')\n }\n }\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'settings.json') : null\n}\n\nasync function detectMCPorter(ctx: DetectionEnv): Promise<string | null> {\n const mcporterDir = path.join(ctx.homedir, '.mcporter')\n if (!ctx.existsSync(mcporterDir)) return null\n\n const jsonPath = path.join(mcporterDir, 'mcporter.json')\n const jsoncPath = path.join(mcporterDir, 'mcporter.jsonc')\n if (ctx.existsSync(jsonPath)) return jsonPath\n if (ctx.existsSync(jsoncPath)) return jsoncPath\n return jsonPath\n}\n\n// -- Read token helpers --\n\n/**\n * Extract a Bearer token from a headers-like object.\n * Looks for `Authorization: \"Bearer <token>\"` and returns the token portion.\n */\nfunction extractBearerToken(headers: unknown): string | undefined {\n if (typeof headers !== 'object' || headers === null) return undefined\n const auth = (headers as Record<string, unknown>).Authorization\n if (typeof auth !== 'string') return undefined\n const match = auth.match(/^Bearer\\s+(.+)$/)\n return match?.[1]\n}\n\nfunction readTokenFromHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.headers)\n}\n\nfunction readTokenFromHttpHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.http_headers)\n}\n\n// -- Defaults & build server config functions --\n\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills'\n/** Most editors share these values — entries only need to declare `detect` + any overrides. */\nconst EDITOR_DEFAULTS = {\n buildServerConfig: defaultHttpConfig,\n configKey: 'mcpServers',\n format: 'jsonc' as const,\n oauthOnly: false,\n readToken: readTokenFromHeaders,\n skillsDir: UNIVERSAL_SKILLS_DIR,\n}\n\nfunction buildAntigravityServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n serverUrl: MCP_SERVER_URL,\n }\n}\n\nfunction buildClineServerConfig(token: string): Record<string, unknown> {\n return {\n disabled: false,\n headers: {Authorization: `Bearer ${token}`},\n type: 'streamableHttp',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildCodexCliServerConfig(token?: string): Record<string, unknown> {\n const config: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.http_headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\n}\n\nfunction buildGitHubCopilotCliServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n tools: ['*'],\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildOpenCodeServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n type: 'remote',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildZedServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n settings: {},\n url: MCP_SERVER_URL,\n }\n}\n\n/**\n * Centralized editor configuration including detection logic.\n * To add a new editor: add an entry here — EditorName type is derived automatically.\n *\n * Each entry includes a doc URL pointing to the source of truth for its\n * config path and format. When updating a path, verify against the linked\n * documentation first.\n */\nexport const EDITOR_CONFIGS = {\n // Doc: https://support.google.com/gemini/answer/16255176 (Antigravity / Project Mariner)\n Antigravity: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildAntigravityServerConfig,\n detect: detectAntigravity,\n skillsCliAgent: 'antigravity',\n },\n // Doc: https://docs.anthropic.com/en/docs/claude-code/mcp\n // Path: ~/.claude.json Key: mcpServers\n 'Claude Code': {\n ...EDITOR_DEFAULTS,\n detect: detectClaudeCode,\n oauthOnly: true,\n skillsCliAgent: 'claude-code',\n skillsDir: '.claude/skills',\n },\n // Doc: https://github.com/cline/cline — VS Code extension (saoudrizwan.claude-dev)\n // Path: <VS Code User>/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n Cline: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectCline,\n skillsCliAgent: 'cline',\n },\n // Doc: https://github.com/cline/cline — standalone CLI mode\n // Path: $CLINE_DIR || ~/.cline/data/settings/cline_mcp_settings.json\n 'Cline CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectClineCli,\n skillsCliAgent: 'cline',\n },\n // Doc: https://platform.openai.com/docs/guides/tools-remote-mcp#codex-cli\n // Path: $CODEX_HOME || ~/.codex/config.toml Key: mcp_servers Format: TOML\n 'Codex CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildCodexCliServerConfig,\n configKey: 'mcp_servers',\n detect: detectCodexCli,\n format: 'toml' as const,\n oauthOnly: true,\n readToken: readTokenFromHttpHeaders,\n skillsCliAgent: 'codex',\n },\n // Doc: https://docs.cursor.com/context/model-context-protocol\n // Path: ~/.cursor/mcp.json Key: mcpServers\n Cursor: {\n ...EDITOR_DEFAULTS,\n detect: detectCursor,\n oauthOnly: true,\n skillsCliAgent: 'cursor',\n },\n // Doc: https://googlegemini.wiki/gemini-cli/mcp-servers\n // Path: ~/.gemini/settings.json Key: mcpServers\n 'Gemini CLI': {...EDITOR_DEFAULTS, detect: detectGeminiCli, skillsCliAgent: 'gemini-cli'},\n // Doc: https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-coding-agent-with-mcp\n // Path: ~/.copilot/mcp-config.json (or $XDG_CONFIG_HOME/copilot on Linux) Key: mcpServers\n 'GitHub Copilot CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildGitHubCopilotCliServerConfig,\n detect: detectGitHubCopilotCli,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://github.com/nicobailon/mcporter\n // Path: ~/.mcporter/mcporter.{json,jsonc} Key: mcpServers\n MCPorter: {...EDITOR_DEFAULTS, detect: detectMCPorter},\n // Doc: https://opencode.ai/docs/config\n // Path: ~/.config/opencode/opencode.json Key: mcp\n OpenCode: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildOpenCodeServerConfig,\n configKey: 'mcp',\n detect: detectOpenCode,\n skillsCliAgent: 'opencode',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code User dir>/mcp.json Key: servers\n // VS Code uses GitHub Copilot for AI features; skills are installed via the\n // `github-copilot` agent (see https://code.visualstudio.com/docs/copilot/customization/agent-skills).\n 'VS Code': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCode,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code Insiders User dir>/mcp.json Key: servers\n 'VS Code Insiders': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCodeInsiders,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://zed.dev/docs/assistant/model-context-protocol\n // Path: ~/.config/zed/settings.json (or $APPDATA/Zed on Windows) Key: context_servers\n // Zed doesn't support agent skills - https://github.com/zed-industries/zed/issues/49057\n Zed: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildZedServerConfig,\n configKey: 'context_servers',\n detect: detectZed,\n },\n} satisfies Record<string, EditorConfig>\n\n/** Derived from EDITOR_CONFIGS keys - add a new editor there and this updates automatically */\nexport type EditorName = keyof typeof EDITOR_CONFIGS\n\nexport function getSkillsCliAgent(editorName: EditorName): string | undefined {\n if (editorName in EDITOR_CONFIGS) {\n const config = EDITOR_CONFIGS[editorName]\n return 'skillsCliAgent' in config ? config.skillsCliAgent : undefined\n }\n}\n\n/**\n * Skills-CLI agent ID → display name. Mirrors `displayName` from\n * `~/git/skills/src/agents.ts` for the subset of agents we install for. Used\n * to match `skills list --json` output (which keys by display name) against\n * our editors.\n */\nconst SKILLS_CLI_AGENT_DISPLAY_NAMES: Record<string, string> = {\n antigravity: 'Antigravity',\n 'claude-code': 'Claude Code',\n cline: 'Cline',\n codex: 'Codex',\n cursor: 'Cursor',\n 'gemini-cli': 'Gemini CLI',\n 'github-copilot': 'GitHub Copilot',\n opencode: 'OpenCode',\n}\n\nexport function isUniversalSkillsCliAgentByEditorName(editorName: EditorName): boolean {\n return EDITOR_CONFIGS[editorName]?.skillsDir === UNIVERSAL_SKILLS_DIR\n}\n\n/** Display name used by the skills CLI for the given editor, if it has a mapping. */\nexport function getSkillsCliAgentDisplayName(editorName: EditorName): string | undefined {\n const agent = getSkillsCliAgent(editorName)\n return agent ? SKILLS_CLI_AGENT_DISPLAY_NAMES[agent] : undefined\n}\n\n/** Display name for a skills-CLI agent ID (e.g. `'cursor'` → `'Cursor'`). */\nexport function getSkillsCliAgentDisplayNameById(agentId: string): string | undefined {\n return SKILLS_CLI_AGENT_DISPLAY_NAMES[agentId]\n}\n\n/**\n * The relative, home-anchored directory the `skills` CLI installs into for a\n * given agent ID (e.g. `'cursor'` → `'.agents/skills'`, `'claude-code'` →\n * `'.claude/skills'`). Derived from `EDITOR_CONFIGS` so it stays a single\n * source of truth.\n */\nexport function getSkillsCliAgentSkillsDir(agentName: string): string | undefined {\n for (const name of Object.keys(EDITOR_CONFIGS) as EditorName[]) {\n const config = EDITOR_CONFIGS[name]\n const agent = getSkillsCliAgent(name)\n if (agent === agentName) {\n return config.skillsDir\n }\n }\n return undefined\n}\n"],"names":["existsSync","os","path","execa","MCP_SERVER_URL","createDetectionEnv","env","process","execCommand","cmd","args","stdio","timeout","then","homedir","platform","defaultHttpConfig","token","defaultConfig","type","url","headers","Authorization","detectClaudeCode","ctx","join","detectAntigravity","antigravityDir","getVSCodeUserDir","variant","APPDATA","detectCline","vscodeUserDir","clineConfigDir","detectClineCli","clineHome","CLINE_DIR","detectCodexCli","codexHome","CODEX_HOME","detectCursor","cursorDir","detectGeminiCli","settingsPath","detectGitHubCopilotCli","copilotDir","XDG_CONFIG_HOME","detectOpenCode","detectVSCode","configDir","detectVSCodeInsiders","detectZed","detectMCPorter","mcporterDir","jsonPath","jsoncPath","extractBearerToken","undefined","auth","match","readTokenFromHeaders","serverConfig","readTokenFromHttpHeaders","http_headers","UNIVERSAL_SKILLS_DIR","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","skillsDir","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","config","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","settings","EDITOR_CONFIGS","Antigravity","detect","skillsCliAgent","Cline","Cursor","MCPorter","OpenCode","Zed","getSkillsCliAgent","editorName","SKILLS_CLI_AGENT_DISPLAY_NAMES","antigravity","cline","codex","cursor","opencode","isUniversalSkillsCliAgentByEditorName","getSkillsCliAgentDisplayName","agent","getSkillsCliAgentDisplayNameById","agentId","getSkillsCliAgentSkillsDir","agentName","name","Object","keys"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/mcp/editorConfigs.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport {execa} from 'execa'\n\nimport {MCP_SERVER_URL} from '../../services/mcp.js'\n\n/**\n * Environment abstraction for editor detection.\n *\n * Detect functions receive this instead of using module-level imports, making\n * each function independently testable without global mocks.\n */\nexport interface DetectionEnv {\n env: Record<string, string | undefined>\n /** Run a CLI command to check if a tool is installed. Rejects on failure. */\n execCommand: (cmd: string, args: string[]) => Promise<void>\n existsSync: (p: string) => boolean\n homedir: string\n platform: NodeJS.Platform\n}\n\n/** Create the real detection environment backed by process/OS globals. */\nexport function createDetectionEnv(): DetectionEnv {\n return {\n env: process.env,\n execCommand: (cmd, args) => execa(cmd, args, {stdio: 'pipe', timeout: 5000}).then(() => {}),\n existsSync,\n homedir: os.homedir(),\n platform: process.platform,\n }\n}\n\ninterface EditorConfig {\n /** Builds the server config with API token. If oauthOnly is true, the token is not used */\n buildServerConfig: (token: string) => Record<string, unknown>\n configKey: string\n /** Returns the config file path if editor is detected, null otherwise */\n detect: (env: DetectionEnv) => Promise<string | null>\n format: 'jsonc' | 'toml'\n /** Extracts the auth token from a parsed Sanity server config block */\n readToken: (serverConfig: Record<string, unknown>) => string | undefined\n\n /** If true, this editor uses OAuth natively and does not need an embedded API token */\n oauthOnly?: boolean\n /**\n * Corresponding `--agent` value for the `skills` CLI (https://github.com/vercel-labs/skills).\n * Omit when the editor has no skills CLI equivalent.\n */\n skillsCliAgent?: string\n /**\n * The directory to install skills to.\n */\n skillsDir?: string\n}\n\n/**\n * The Sanity MCP server uses OAuth by default\n * If a token is provided, the server will not use OAuth instead tool calls will use the API token\n */\nconst defaultHttpConfig = (token?: string) => {\n const defaultConfig: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n defaultConfig.headers = {Authorization: `Bearer ${token}`}\n }\n\n return defaultConfig\n}\n\n// -- Detect functions --\n\nasync function detectClaudeCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('claude', ['--version'])\n return path.join(ctx.homedir, '.claude.json')\n } catch {\n return null\n }\n}\n\nasync function detectAntigravity(ctx: DetectionEnv): Promise<string | null> {\n const antigravityDir = path.join(ctx.homedir, '.gemini/antigravity')\n return ctx.existsSync(antigravityDir) ? path.join(antigravityDir, 'mcp_config.json') : null\n}\n\nexport function getVSCodeUserDir(\n ctx: DetectionEnv,\n variant: 'insiders' | 'stable' = 'stable',\n): string | null {\n switch (ctx.platform) {\n case 'darwin': {\n return path.join(\n ctx.homedir,\n variant === 'insiders'\n ? 'Library/Application Support/Code - Insiders/User'\n : 'Library/Application Support/Code/User',\n )\n }\n case 'win32': {\n if (!ctx.env.APPDATA) return null\n return path.join(\n ctx.env.APPDATA,\n variant === 'insiders' ? 'Code - Insiders/User' : 'Code/User',\n )\n }\n default: {\n return path.join(\n ctx.homedir,\n variant === 'insiders' ? '.config/Code - Insiders/User' : '.config/Code/User',\n )\n }\n }\n}\n\nasync function detectCline(ctx: DetectionEnv): Promise<string | null> {\n const vscodeUserDir = getVSCodeUserDir(ctx)\n if (!vscodeUserDir) return null\n const clineConfigDir = path.join(vscodeUserDir, 'globalStorage/saoudrizwan.claude-dev/settings')\n return ctx.existsSync(clineConfigDir)\n ? path.join(clineConfigDir, 'cline_mcp_settings.json')\n : null\n}\n\nasync function detectClineCli(ctx: DetectionEnv): Promise<string | null> {\n const clineHome = ctx.env.CLINE_DIR || path.join(ctx.homedir, '.cline')\n if (!ctx.existsSync(clineHome)) return null\n return path.join(clineHome, 'data/settings/cline_mcp_settings.json')\n}\n\nasync function detectCodexCli(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('codex', ['--version'])\n const codexHome = ctx.env.CODEX_HOME || path.join(ctx.homedir, '.codex')\n return path.join(codexHome, 'config.toml')\n } catch {\n return null\n }\n}\n\nasync function detectCursor(ctx: DetectionEnv): Promise<string | null> {\n const cursorDir = path.join(ctx.homedir, '.cursor')\n return ctx.existsSync(cursorDir) ? path.join(cursorDir, 'mcp.json') : null\n}\n\nasync function detectGeminiCli(ctx: DetectionEnv): Promise<string | null> {\n // Antigravity stores its config under ~/.gemini/antigravity, so checking\n // only the parent ~/.gemini directory causes false Gemini CLI detection.\n const settingsPath = path.join(ctx.homedir, '.gemini/settings.json')\n return ctx.existsSync(settingsPath) ? settingsPath : null\n}\n\nasync function detectGitHubCopilotCli(ctx: DetectionEnv): Promise<string | null> {\n const copilotDir =\n ctx.platform === 'linux' && ctx.env.XDG_CONFIG_HOME\n ? path.join(ctx.env.XDG_CONFIG_HOME, 'copilot')\n : path.join(ctx.homedir, '.copilot')\n return ctx.existsSync(copilotDir) ? path.join(copilotDir, 'mcp-config.json') : null\n}\n\nasync function detectOpenCode(ctx: DetectionEnv): Promise<string | null> {\n try {\n await ctx.execCommand('opencode', ['--version'])\n return path.join(ctx.homedir, '.config/opencode/opencode.json')\n } catch {\n return null\n }\n}\n\nasync function detectVSCode(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx)\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectVSCodeInsiders(ctx: DetectionEnv): Promise<string | null> {\n const configDir = getVSCodeUserDir(ctx, 'insiders')\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'mcp.json') : null\n}\n\nasync function detectZed(ctx: DetectionEnv): Promise<string | null> {\n let configDir: string | null = null\n switch (ctx.platform) {\n case 'win32': {\n if (ctx.env.APPDATA) {\n configDir = path.join(ctx.env.APPDATA, 'Zed')\n }\n break\n }\n default: {\n configDir = path.join(ctx.homedir, '.config/zed')\n }\n }\n return configDir && ctx.existsSync(configDir) ? path.join(configDir, 'settings.json') : null\n}\n\nasync function detectMCPorter(ctx: DetectionEnv): Promise<string | null> {\n const mcporterDir = path.join(ctx.homedir, '.mcporter')\n if (!ctx.existsSync(mcporterDir)) return null\n\n const jsonPath = path.join(mcporterDir, 'mcporter.json')\n const jsoncPath = path.join(mcporterDir, 'mcporter.jsonc')\n if (ctx.existsSync(jsonPath)) return jsonPath\n if (ctx.existsSync(jsoncPath)) return jsoncPath\n return jsonPath\n}\n\n// -- Read token helpers --\n\n/**\n * Extract a Bearer token from a headers-like object.\n * Looks for `Authorization: \"Bearer <token>\"` and returns the token portion.\n */\nfunction extractBearerToken(headers: unknown): string | undefined {\n if (typeof headers !== 'object' || headers === null) return undefined\n const auth = (headers as Record<string, unknown>).Authorization\n if (typeof auth !== 'string') return undefined\n const match = auth.match(/^Bearer\\s+(.+)$/)\n return match?.[1]\n}\n\nfunction readTokenFromHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.headers)\n}\n\nfunction readTokenFromHttpHeaders(serverConfig: Record<string, unknown>): string | undefined {\n return extractBearerToken(serverConfig.http_headers)\n}\n\n// -- Defaults & build server config functions --\n\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills'\n/** Most editors share these values — entries only need to declare `detect` + any overrides. */\nconst EDITOR_DEFAULTS = {\n buildServerConfig: defaultHttpConfig,\n configKey: 'mcpServers',\n format: 'jsonc' as const,\n oauthOnly: false,\n readToken: readTokenFromHeaders,\n skillsDir: UNIVERSAL_SKILLS_DIR,\n}\n\nfunction buildAntigravityServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n serverUrl: MCP_SERVER_URL,\n }\n}\n\nfunction buildClineServerConfig(token: string): Record<string, unknown> {\n return {\n disabled: false,\n headers: {Authorization: `Bearer ${token}`},\n type: 'streamableHttp',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildCodexCliServerConfig(token?: string): Record<string, unknown> {\n const config: Record<string, unknown> = {\n type: 'http',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.http_headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\n}\n\nfunction buildGitHubCopilotCliServerConfig(token: string): Record<string, unknown> {\n return {\n headers: {Authorization: `Bearer ${token}`},\n tools: ['*'],\n type: 'http',\n url: MCP_SERVER_URL,\n }\n}\n\nfunction buildOpenCodeServerConfig(token?: string): Record<string, unknown> {\n const config: Record<string, unknown> = {\n type: 'remote',\n url: MCP_SERVER_URL,\n }\n\n if (token) {\n config.headers = {Authorization: `Bearer ${token}`}\n }\n\n return config\n}\n\nfunction buildZedServerConfig(token: string): Record<string, unknown> {\n return {\n enabled: true,\n headers: {Authorization: `Bearer ${token}`},\n url: MCP_SERVER_URL,\n }\n}\n\n/**\n * Centralized editor configuration including detection logic.\n * To add a new editor: add an entry here — EditorName type is derived automatically.\n *\n * Each entry includes a doc URL pointing to the source of truth for its\n * config path and format. When updating a path, verify against the linked\n * documentation first.\n */\nexport const EDITOR_CONFIGS = {\n // Doc: https://support.google.com/gemini/answer/16255176 (Antigravity / Project Mariner)\n Antigravity: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildAntigravityServerConfig,\n detect: detectAntigravity,\n skillsCliAgent: 'antigravity',\n },\n // Doc: https://docs.anthropic.com/en/docs/claude-code/mcp\n // Path: ~/.claude.json Key: mcpServers\n 'Claude Code': {\n ...EDITOR_DEFAULTS,\n detect: detectClaudeCode,\n oauthOnly: true,\n skillsCliAgent: 'claude-code',\n skillsDir: '.claude/skills',\n },\n // Doc: https://github.com/cline/cline — VS Code extension (saoudrizwan.claude-dev)\n // Path: <VS Code User>/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n Cline: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectCline,\n skillsCliAgent: 'cline',\n },\n // Doc: https://github.com/cline/cline — standalone CLI mode\n // Path: $CLINE_DIR || ~/.cline/data/settings/cline_mcp_settings.json\n 'Cline CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildClineServerConfig,\n detect: detectClineCli,\n skillsCliAgent: 'cline',\n },\n // Doc: https://platform.openai.com/docs/guides/tools-remote-mcp#codex-cli\n // Path: $CODEX_HOME || ~/.codex/config.toml Key: mcp_servers Format: TOML\n 'Codex CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildCodexCliServerConfig,\n configKey: 'mcp_servers',\n detect: detectCodexCli,\n format: 'toml' as const,\n oauthOnly: true,\n readToken: readTokenFromHttpHeaders,\n skillsCliAgent: 'codex',\n },\n // Doc: https://docs.cursor.com/context/model-context-protocol\n // Path: ~/.cursor/mcp.json Key: mcpServers\n Cursor: {\n ...EDITOR_DEFAULTS,\n detect: detectCursor,\n oauthOnly: true,\n skillsCliAgent: 'cursor',\n },\n // Doc: https://googlegemini.wiki/gemini-cli/mcp-servers\n // Path: ~/.gemini/settings.json Key: mcpServers\n 'Gemini CLI': {...EDITOR_DEFAULTS, detect: detectGeminiCli, skillsCliAgent: 'gemini-cli'},\n // Doc: https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-coding-agent-with-mcp\n // Path: ~/.copilot/mcp-config.json (or $XDG_CONFIG_HOME/copilot on Linux) Key: mcpServers\n 'GitHub Copilot CLI': {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildGitHubCopilotCliServerConfig,\n detect: detectGitHubCopilotCli,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://github.com/nicobailon/mcporter\n // Path: ~/.mcporter/mcporter.{json,jsonc} Key: mcpServers\n MCPorter: {...EDITOR_DEFAULTS, detect: detectMCPorter},\n // Doc: https://opencode.ai/docs/config\n // Path: ~/.config/opencode/opencode.json Key: mcp\n OpenCode: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildOpenCodeServerConfig,\n configKey: 'mcp',\n detect: detectOpenCode,\n oauthOnly: true,\n skillsCliAgent: 'opencode',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code User dir>/mcp.json Key: servers\n // VS Code uses GitHub Copilot for AI features; skills are installed via the\n // `github-copilot` agent (see https://code.visualstudio.com/docs/copilot/customization/agent-skills).\n 'VS Code': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCode,\n oauthOnly: true,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://code.visualstudio.com/docs/copilot/chat/mcp-servers\n // Path: <VS Code Insiders User dir>/mcp.json Key: servers\n 'VS Code Insiders': {\n ...EDITOR_DEFAULTS,\n configKey: 'servers',\n detect: detectVSCodeInsiders,\n oauthOnly: true,\n skillsCliAgent: 'github-copilot',\n },\n // Doc: https://zed.dev/docs/assistant/model-context-protocol\n // Path: ~/.config/zed/settings.json (or $APPDATA/Zed on Windows) Key: context_servers\n // Zed doesn't support agent skills - https://github.com/zed-industries/zed/issues/49057\n Zed: {\n ...EDITOR_DEFAULTS,\n buildServerConfig: buildZedServerConfig,\n configKey: 'context_servers',\n detect: detectZed,\n },\n} satisfies Record<string, EditorConfig>\n\n/** Derived from EDITOR_CONFIGS keys - add a new editor there and this updates automatically */\nexport type EditorName = keyof typeof EDITOR_CONFIGS\n\nexport function getSkillsCliAgent(editorName: EditorName): string | undefined {\n if (editorName in EDITOR_CONFIGS) {\n const config = EDITOR_CONFIGS[editorName]\n return 'skillsCliAgent' in config ? config.skillsCliAgent : undefined\n }\n}\n\n/**\n * Skills-CLI agent ID → display name. Mirrors `displayName` from\n * `~/git/skills/src/agents.ts` for the subset of agents we install for. Used\n * to match `skills list --json` output (which keys by display name) against\n * our editors.\n */\nconst SKILLS_CLI_AGENT_DISPLAY_NAMES: Record<string, string> = {\n antigravity: 'Antigravity',\n 'claude-code': 'Claude Code',\n cline: 'Cline',\n codex: 'Codex',\n cursor: 'Cursor',\n 'gemini-cli': 'Gemini CLI',\n 'github-copilot': 'GitHub Copilot',\n opencode: 'OpenCode',\n}\n\nexport function isUniversalSkillsCliAgentByEditorName(editorName: EditorName): boolean {\n return EDITOR_CONFIGS[editorName]?.skillsDir === UNIVERSAL_SKILLS_DIR\n}\n\n/** Display name used by the skills CLI for the given editor, if it has a mapping. */\nexport function getSkillsCliAgentDisplayName(editorName: EditorName): string | undefined {\n const agent = getSkillsCliAgent(editorName)\n return agent ? SKILLS_CLI_AGENT_DISPLAY_NAMES[agent] : undefined\n}\n\n/** Display name for a skills-CLI agent ID (e.g. `'cursor'` → `'Cursor'`). */\nexport function getSkillsCliAgentDisplayNameById(agentId: string): string | undefined {\n return SKILLS_CLI_AGENT_DISPLAY_NAMES[agentId]\n}\n\n/**\n * The relative, home-anchored directory the `skills` CLI installs into for a\n * given agent ID (e.g. `'cursor'` → `'.agents/skills'`, `'claude-code'` →\n * `'.claude/skills'`). Derived from `EDITOR_CONFIGS` so it stays a single\n * source of truth.\n */\nexport function getSkillsCliAgentSkillsDir(agentName: string): string | undefined {\n for (const name of Object.keys(EDITOR_CONFIGS) as EditorName[]) {\n const config = EDITOR_CONFIGS[name]\n const agent = getSkillsCliAgent(name)\n if (agent === agentName) {\n return config.skillsDir\n }\n }\n return undefined\n}\n"],"names":["existsSync","os","path","execa","MCP_SERVER_URL","createDetectionEnv","env","process","execCommand","cmd","args","stdio","timeout","then","homedir","platform","defaultHttpConfig","token","defaultConfig","type","url","headers","Authorization","detectClaudeCode","ctx","join","detectAntigravity","antigravityDir","getVSCodeUserDir","variant","APPDATA","detectCline","vscodeUserDir","clineConfigDir","detectClineCli","clineHome","CLINE_DIR","detectCodexCli","codexHome","CODEX_HOME","detectCursor","cursorDir","detectGeminiCli","settingsPath","detectGitHubCopilotCli","copilotDir","XDG_CONFIG_HOME","detectOpenCode","detectVSCode","configDir","detectVSCodeInsiders","detectZed","detectMCPorter","mcporterDir","jsonPath","jsoncPath","extractBearerToken","undefined","auth","match","readTokenFromHeaders","serverConfig","readTokenFromHttpHeaders","http_headers","UNIVERSAL_SKILLS_DIR","EDITOR_DEFAULTS","buildServerConfig","configKey","format","oauthOnly","readToken","skillsDir","buildAntigravityServerConfig","serverUrl","buildClineServerConfig","disabled","buildCodexCliServerConfig","config","buildGitHubCopilotCliServerConfig","tools","buildOpenCodeServerConfig","buildZedServerConfig","enabled","EDITOR_CONFIGS","Antigravity","detect","skillsCliAgent","Cline","Cursor","MCPorter","OpenCode","Zed","getSkillsCliAgent","editorName","SKILLS_CLI_AGENT_DISPLAY_NAMES","antigravity","cline","codex","cursor","opencode","isUniversalSkillsCliAgentByEditorName","getSkillsCliAgentDisplayName","agent","getSkillsCliAgentDisplayNameById","agentId","getSkillsCliAgentSkillsDir","agentName","name","Object","keys"],"mappings":"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"}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0",
|
|
4
4
|
"description": "Sanity CLI tool for managing Sanity projects and organizations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -114,17 +114,17 @@
|
|
|
114
114
|
"tinyglobby": "^0.2.17",
|
|
115
115
|
"tsx": "^4.22.4",
|
|
116
116
|
"typeid-js": "^1.2.0",
|
|
117
|
-
"vite": "^8.1.
|
|
117
|
+
"vite": "^8.1.2",
|
|
118
118
|
"which": "^6.0.1",
|
|
119
119
|
"yaml": "^2.9.0",
|
|
120
120
|
"zod": "^4.4.3",
|
|
121
|
-
"@sanity/
|
|
122
|
-
"@sanity/cli
|
|
123
|
-
"@sanity/cli-
|
|
121
|
+
"@sanity/cli-build": "^2.0.1",
|
|
122
|
+
"@sanity/workbench-cli": "^1.1.3",
|
|
123
|
+
"@sanity/cli-core": "^2.1.3"
|
|
124
124
|
},
|
|
125
125
|
"devDependencies": {
|
|
126
126
|
"@eslint/compat": "^2.1.0",
|
|
127
|
-
"@sanity/pkg-utils": "^10.
|
|
127
|
+
"@sanity/pkg-utils": "^10.8.1",
|
|
128
128
|
"@sanity/ui": "^3.2.0",
|
|
129
129
|
"@swc/cli": "^0.8.1",
|
|
130
130
|
"@swc/core": "^1.15.41",
|
|
@@ -156,8 +156,8 @@
|
|
|
156
156
|
"vitest": "^4.1.9",
|
|
157
157
|
"@repo/package.config": "0.0.1",
|
|
158
158
|
"@repo/tsconfig": "3.70.0",
|
|
159
|
-
"@sanity/cli
|
|
160
|
-
"@sanity/
|
|
159
|
+
"@sanity/eslint-config-cli": "1.1.2",
|
|
160
|
+
"@sanity/cli-test": "2.0.3"
|
|
161
161
|
},
|
|
162
162
|
"peerDependencies": {
|
|
163
163
|
"babel-plugin-react-compiler": "*"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sanity-app-sdk
|
|
3
|
+
description: Build features with the Sanity App SDK (@sanity/sdk-react). Use when adding components, fetching or editing Sanity content, or working with hooks like useDocuments, useDocument, useDocumentProjection, useEditDocument, or useQuery.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sanity App SDK
|
|
7
|
+
|
|
8
|
+
## Get the maintained guide first
|
|
9
|
+
|
|
10
|
+
If the Sanity MCP server is configured, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is maintained by Sanity, is more detailed, and supersedes the notes below. The notes below are a fallback for when MCP is not available.
|
|
11
|
+
|
|
12
|
+
## Picking a hook
|
|
13
|
+
|
|
14
|
+
- `useDocuments` / `usePaginatedDocuments`: lists of documents. Returns document handles, not full documents.
|
|
15
|
+
- `useDocumentProjection`: read specific fields from a handle, for display.
|
|
16
|
+
- `useDocument` plus `useEditDocument`: read and write a single document in real time.
|
|
17
|
+
- `useQuery`: raw GROQ. Use sparingly; prefer handles plus projections.
|
|
18
|
+
|
|
19
|
+
## Document handles
|
|
20
|
+
|
|
21
|
+
Fetch handles first, then spread them into other hooks:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
const {data} = useDocuments({documentType: 'article'})
|
|
25
|
+
|
|
26
|
+
// in a child component receiving one handle:
|
|
27
|
+
const {data: fields} = useDocumentProjection({...handle, projection: '{title}'})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `documentId` as the React key when rendering lists, never the array index.
|
|
31
|
+
|
|
32
|
+
## Suspense
|
|
33
|
+
|
|
34
|
+
Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>` with a fallback, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`. All SDK hooks must be used inside `SanityApp`.
|
|
35
|
+
|
|
36
|
+
## Editing
|
|
37
|
+
|
|
38
|
+
Write through `useEditDocument` on change so content stays in sync with the Content Lake:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const {data: title} = useDocument({...handle, path: 'title'})
|
|
42
|
+
const editTitle = useEditDocument({...handle, path: 'title'})
|
|
43
|
+
// <input value={title ?? ''} onChange={(e) => editTitle(e.currentTarget.value)} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Do not hold document field values in `useState` and save on submit. That pattern goes stale and loses concurrent edits.
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
Fetch these for current detail rather than relying on the notes above:
|
|
51
|
+
|
|
52
|
+
- Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
|
|
53
|
+
- Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
|
|
54
|
+
- Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
|
|
55
|
+
- Deployment: https://www.sanity.io/docs/app-sdk/sdk-deployment
|
|
56
|
+
- API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
A React application built with the Sanity App SDK (`@sanity/sdk-react`). It is not a Sanity Studio. The app reads and writes content in a Sanity project through SDK hooks, and runs inside the organization's Sanity Dashboard, in development and when deployed. The `sanity` CLI runs it with Vite under the hood.
|
|
8
|
+
|
|
9
|
+
## Key files
|
|
10
|
+
|
|
11
|
+
- `src/App.tsx`: entry point. The `SanityApp` component takes a `config` array with `projectId` and `dataset`. All SDK hooks must be used inside `SanityApp`.
|
|
12
|
+
- `sanity.cli.ts`: CLI config with the organization ID and app entry path.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
- `npm run dev`: starts the dev server on port 3333, but the app only renders inside the Sanity Dashboard. The CLI prints a Dashboard URL to open. Viewing it requires a signed-in Sanity account, so a human must complete authentication in the browser.
|
|
17
|
+
- `npm run build`: production build.
|
|
18
|
+
- `npm run deploy`: deploy to the Sanity Dashboard.
|
|
19
|
+
|
|
20
|
+
Environment variables prefixed with `SANITY_APP_` are bundled into the app.
|
|
21
|
+
|
|
22
|
+
## Working with the App SDK
|
|
23
|
+
|
|
24
|
+
If the Sanity MCP server is available, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is the maintained guide and supersedes the notes below.
|
|
25
|
+
|
|
26
|
+
Essentials:
|
|
27
|
+
|
|
28
|
+
- Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>`, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`.
|
|
29
|
+
- Fetch lists with `useDocuments` (or `usePaginatedDocuments`). They return document handles, not full documents. Spread a handle into `useDocumentProjection` to display fields, or into `useDocument` and `useEditDocument` for real-time editing.
|
|
30
|
+
- Use `documentId` as the React key when rendering document lists, never the array index.
|
|
31
|
+
- Do not hold document field values in `useState` and save on submit. Write through `useEditDocument` on change so content stays in sync with the Content Lake.
|
|
32
|
+
- Prefer handles plus projections over raw GROQ. Reach for `useQuery` only when a complex query genuinely needs it.
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
- App SDK docs: https://www.sanity.io/docs/app-sdk
|
|
37
|
+
- Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
|
|
38
|
+
- Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
|
|
39
|
+
- Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
|
|
40
|
+
- API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Sanity App
|
|
2
|
+
|
|
3
|
+
A custom application built with the [Sanity App SDK](https://www.sanity.io/docs/app-sdk?utm_source=readme). It is a React app that runs inside your organization's Sanity Dashboard, in development and when deployed.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `npm run dev` starts the dev server and prints a Sanity Dashboard URL where your app runs. Open it and sign in with your Sanity account.
|
|
8
|
+
- `npm run build` builds the app for production.
|
|
9
|
+
- `npm run deploy` deploys the app to the Sanity Dashboard.
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
- `src/App.tsx` is the app entry point. The `SanityApp` config sets which project and dataset the app reads content from.
|
|
14
|
+
- `sanity.cli.ts` holds your organization ID and the app entry path.
|
|
15
|
+
|
|
16
|
+
## Learn more
|
|
17
|
+
|
|
18
|
+
- [App SDK Quickstart Guide](https://www.sanity.io/docs/app-sdk/sdk-quickstart?utm_source=readme)
|
|
19
|
+
- [App SDK documentation](https://www.sanity.io/docs/app-sdk?utm_source=readme)
|
|
20
|
+
- [API reference](https://reference.sanity.io/_sanity/sdk-react/)
|
|
21
|
+
- [Deploying your app](https://www.sanity.io/docs/app-sdk/sdk-deployment?utm_source=readme)
|
|
22
|
+
- [SDK Explorer with example apps](https://sdk-explorer.sanity.io)
|
|
@@ -17,21 +17,42 @@ export function ExampleComponent() {
|
|
|
17
17
|
Welcome to your Sanity App{user?.name ? `, ${user.name}` : ''}!
|
|
18
18
|
</h1>
|
|
19
19
|
<p className="example-text">
|
|
20
|
-
This is an example component
|
|
21
|
-
|
|
20
|
+
This is an example component, rendered with the <code>useCurrentUser</code> hook from the
|
|
21
|
+
App SDK. Replace it with your own components by importing them in App.tsx.
|
|
22
22
|
</p>
|
|
23
23
|
<div className="code-hint">
|
|
24
24
|
<p>
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
A good next step is fetching content. Data hooks like <code>useDocuments</code> suspend
|
|
26
|
+
while loading, so render them inside a <code>{'<Suspense>'}</code> boundary:
|
|
27
27
|
</p>
|
|
28
|
-
<pre>{`import {
|
|
28
|
+
<pre>{`import {Suspense} from 'react'
|
|
29
|
+
import {useDocuments} from '@sanity/sdk-react'
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
</
|
|
31
|
+
function DocumentList() {
|
|
32
|
+
// useDocuments returns handles you can pass to other hooks
|
|
33
|
+
const {data} = useDocuments({documentType: 'yourType'})
|
|
34
|
+
return <ul>{data.map((doc) => <li key={doc.documentId}>{doc.documentId}</li>)}</ul>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function App() {
|
|
38
|
+
return (
|
|
39
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
40
|
+
<DocumentList />
|
|
41
|
+
</Suspense>
|
|
42
|
+
)
|
|
43
|
+
}`}</pre>
|
|
34
44
|
</div>
|
|
45
|
+
<ul className="example-links">
|
|
46
|
+
<li>
|
|
47
|
+
<a href="https://www.sanity.io/docs/app-sdk">App SDK documentation</a>
|
|
48
|
+
</li>
|
|
49
|
+
<li>
|
|
50
|
+
<a href="https://reference.sanity.io/_sanity/sdk-react/">API reference</a>
|
|
51
|
+
</li>
|
|
52
|
+
<li>
|
|
53
|
+
<a href="https://sdk-explorer.sanity.io">SDK Explorer with example apps</a>
|
|
54
|
+
</li>
|
|
55
|
+
</ul>
|
|
35
56
|
</div>
|
|
36
57
|
)
|
|
37
58
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sanity-app-sdk
|
|
3
|
+
description: Build features with the Sanity App SDK (@sanity/sdk-react) and Sanity UI. Use when adding components, fetching or editing Sanity content, or working with hooks like useDocuments, useDocument, useDocumentProjection, useEditDocument, or useQuery.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sanity App SDK
|
|
7
|
+
|
|
8
|
+
## Get the maintained guide first
|
|
9
|
+
|
|
10
|
+
If the Sanity MCP server is configured, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is maintained by Sanity, is more detailed, and supersedes the notes below. The notes below are a fallback for when MCP is not available.
|
|
11
|
+
|
|
12
|
+
## Picking a hook
|
|
13
|
+
|
|
14
|
+
- `useDocuments` / `usePaginatedDocuments`: lists of documents. Returns document handles, not full documents.
|
|
15
|
+
- `useDocumentProjection`: read specific fields from a handle, for display.
|
|
16
|
+
- `useDocument` plus `useEditDocument`: read and write a single document in real time.
|
|
17
|
+
- `useQuery`: raw GROQ. Use sparingly; prefer handles plus projections.
|
|
18
|
+
|
|
19
|
+
## Document handles
|
|
20
|
+
|
|
21
|
+
Fetch handles first, then spread them into other hooks:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
const {data} = useDocuments({documentType: 'article'})
|
|
25
|
+
|
|
26
|
+
// in a child component receiving one handle:
|
|
27
|
+
const {data: fields} = useDocumentProjection({...handle, projection: '{title}'})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `documentId` as the React key when rendering lists, never the array index.
|
|
31
|
+
|
|
32
|
+
## Suspense
|
|
33
|
+
|
|
34
|
+
Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>` with a fallback, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`. All SDK hooks must be used inside `SanityApp`.
|
|
35
|
+
|
|
36
|
+
## Editing
|
|
37
|
+
|
|
38
|
+
Write through `useEditDocument` on change so content stays in sync with the Content Lake:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const {data: title} = useDocument({...handle, path: 'title'})
|
|
42
|
+
const editTitle = useEditDocument({...handle, path: 'title'})
|
|
43
|
+
// <input value={title ?? ''} onChange={(e) => editTitle(e.currentTarget.value)} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Do not hold document field values in `useState` and save on submit. That pattern goes stale and loses concurrent edits.
|
|
47
|
+
|
|
48
|
+
## Sanity UI
|
|
49
|
+
|
|
50
|
+
This app wraps everything in Sanity UI's `ThemeProvider` (see `src/SanityUI.tsx`, built with `buildTheme()`). Build UI with Sanity UI primitives like `Card`, `Stack`, `Flex`, `Text`, and `Button`. See https://www.sanity.io/docs/app-sdk/sanity-ui-sdk and https://www.sanity.io/ui.
|
|
51
|
+
|
|
52
|
+
## Documentation
|
|
53
|
+
|
|
54
|
+
Fetch these for current detail rather than relying on the notes above:
|
|
55
|
+
|
|
56
|
+
- Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
|
|
57
|
+
- Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
|
|
58
|
+
- Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
|
|
59
|
+
- Deployment: https://www.sanity.io/docs/app-sdk/sdk-deployment
|
|
60
|
+
- API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
A React application built with the Sanity App SDK (`@sanity/sdk-react`) and Sanity UI (`@sanity/ui`). It is not a Sanity Studio. The app reads and writes content in a Sanity project through SDK hooks, and runs inside the organization's Sanity Dashboard, in development and when deployed. The `sanity` CLI runs it with Vite under the hood.
|
|
8
|
+
|
|
9
|
+
## Key files
|
|
10
|
+
|
|
11
|
+
- `src/App.tsx`: entry point. The `SanityApp` component takes a `config` array with `projectId` and `dataset`. All SDK hooks must be used inside `SanityApp`.
|
|
12
|
+
- `src/SanityUI.tsx`: wraps the app in Sanity UI's `ThemeProvider` with a theme from `buildTheme()`. Sanity UI components must render inside this provider.
|
|
13
|
+
- `sanity.cli.ts`: CLI config with the organization ID and app entry path.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
- `npm run dev`: starts the dev server on port 3333, but the app only renders inside the Sanity Dashboard. The CLI prints a Dashboard URL to open. Viewing it requires a signed-in Sanity account, so a human must complete authentication in the browser.
|
|
18
|
+
- `npm run build`: production build.
|
|
19
|
+
- `npm run deploy`: deploy to the Sanity Dashboard.
|
|
20
|
+
|
|
21
|
+
Environment variables prefixed with `SANITY_APP_` are bundled into the app.
|
|
22
|
+
|
|
23
|
+
## Working with the App SDK
|
|
24
|
+
|
|
25
|
+
If the Sanity MCP server is available, call its `get_sanity_rules` tool with the `app-sdk` rule before writing SDK code. That rule is the maintained guide and supersedes the notes below.
|
|
26
|
+
|
|
27
|
+
Essentials:
|
|
28
|
+
|
|
29
|
+
- Data hooks suspend while loading. Wrap every data-fetching component in `<Suspense>`, keep one fetching hook per component, and always pass a `fallback` to `SanityApp`.
|
|
30
|
+
- Fetch lists with `useDocuments` (or `usePaginatedDocuments`). They return document handles, not full documents. Spread a handle into `useDocumentProjection` to display fields, or into `useDocument` and `useEditDocument` for real-time editing.
|
|
31
|
+
- Use `documentId` as the React key when rendering document lists, never the array index.
|
|
32
|
+
- Do not hold document field values in `useState` and save on submit. Write through `useEditDocument` on change so content stays in sync with the Content Lake.
|
|
33
|
+
- Prefer handles plus projections over raw GROQ. Reach for `useQuery` only when a complex query genuinely needs it.
|
|
34
|
+
- Build UI with Sanity UI primitives like `Card`, `Stack`, `Flex`, `Text`, and `Button` for a look consistent with Sanity tooling.
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
- App SDK docs: https://www.sanity.io/docs/app-sdk
|
|
39
|
+
- Best practices: https://www.sanity.io/docs/app-sdk/sdk-best-practices
|
|
40
|
+
- Editing documents: https://www.sanity.io/docs/app-sdk/editing-documents
|
|
41
|
+
- Configuration: https://www.sanity.io/docs/app-sdk/sdk-configuration
|
|
42
|
+
- Sanity UI with the App SDK: https://www.sanity.io/docs/app-sdk/sanity-ui-sdk
|
|
43
|
+
- Sanity UI docs: https://www.sanity.io/ui
|
|
44
|
+
- API reference with current signatures: https://reference.sanity.io/_sanity/sdk-react/
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Sanity App
|
|
2
|
+
|
|
3
|
+
A custom application built with the [Sanity App SDK](https://www.sanity.io/docs/app-sdk?utm_source=readme) and [Sanity UI](https://www.sanity.io/ui?utm_source=readme). It is a React app that runs inside your organization's Sanity Dashboard, in development and when deployed.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `npm run dev` starts the dev server and prints a Sanity Dashboard URL where your app runs. Open it and sign in with your Sanity account.
|
|
8
|
+
- `npm run build` builds the app for production.
|
|
9
|
+
- `npm run deploy` deploys the app to the Sanity Dashboard.
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
- `src/App.tsx` is the app entry point. The `SanityApp` config sets which project and dataset the app reads content from.
|
|
14
|
+
- `sanity.cli.ts` holds your organization ID and the app entry path.
|
|
15
|
+
|
|
16
|
+
## Learn more
|
|
17
|
+
|
|
18
|
+
- [App SDK Quickstart Guide](https://www.sanity.io/docs/app-sdk/sdk-quickstart?utm_source=readme)
|
|
19
|
+
- [App SDK documentation](https://www.sanity.io/docs/app-sdk?utm_source=readme)
|
|
20
|
+
- [Using Sanity UI with the App SDK](https://www.sanity.io/docs/app-sdk/sanity-ui-sdk?utm_source=readme)
|
|
21
|
+
- [API reference](https://reference.sanity.io/_sanity/sdk-react/)
|
|
22
|
+
- [Deploying your app](https://www.sanity.io/docs/app-sdk/sdk-deployment?utm_source=readme)
|
|
23
|
+
- [SDK Explorer with example apps](https://sdk-explorer.sanity.io)
|
|
@@ -18,13 +18,16 @@ export function ExampleComponent() {
|
|
|
18
18
|
</Text>
|
|
19
19
|
<Text muted>
|
|
20
20
|
You can also replace this component with components of your own. Render them in your
|
|
21
|
-
app by importing and using them in your application’s <code>src/App.tsx
|
|
22
|
-
|
|
21
|
+
app by importing and using them in your application’s <code>src/App.tsx</code> file. A
|
|
22
|
+
good next step is fetching content with the <code>useDocuments</code> hook. Data hooks
|
|
23
|
+
suspend while loading, so render them inside a <code>{'<Suspense>'}</code> boundary.
|
|
23
24
|
</Text>
|
|
24
25
|
<Text muted>
|
|
25
|
-
Looking for more guidance? See the
|
|
26
|
-
|
|
27
|
-
<a href="https://reference.sanity.io/_sanity/sdk-react/">
|
|
26
|
+
Looking for more guidance? See the{' '}
|
|
27
|
+
<a href="https://www.sanity.io/docs/app-sdk">App SDK documentation</a>, the{' '}
|
|
28
|
+
<a href="https://reference.sanity.io/_sanity/sdk-react/">API reference</a>, the{' '}
|
|
29
|
+
<a href="https://sanity.io/ui">Sanity UI docs</a>, and example apps in the{' '}
|
|
30
|
+
<a href="https://sdk-explorer.sanity.io">SDK Explorer</a>.
|
|
28
31
|
</Text>
|
|
29
32
|
</Stack>
|
|
30
33
|
</Flex>
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { buildDebug, copyDir, extendViteConfigWithUserConfig, finalizeViteConfig, getViteConfig, resolveEntries, writeFavicons, writeSanityRuntime } from '@sanity/cli-build/_internal/build';
|
|
3
|
-
import { getAppEnvironmentVariables, getStudioEnvironmentVariables } from '@sanity/cli-build/_internal/env';
|
|
4
|
-
import { build, createBuilder } from 'vite';
|
|
5
|
-
/**
|
|
6
|
-
* Builds static files
|
|
7
|
-
*
|
|
8
|
-
* @internal
|
|
9
|
-
*/ export async function buildStaticFiles(options) {
|
|
10
|
-
const { appTitle, autoUpdates, basePath, cwd, entry, isApp, isWorkbenchApp, minify = true, outputDir, reactCompiler, schemaExtraction, services, sourceMap = false, views, vite: extendViteConfig } = options;
|
|
11
|
-
const mode = 'production';
|
|
12
|
-
/* Federation builds only produce the federation environment
|
|
13
|
-
* (remote-entry, mf-manifest) — skip client-specific steps like
|
|
14
|
-
* runtime generation, static file copies, and favicons.
|
|
15
|
-
*/ if (isWorkbenchApp) {
|
|
16
|
-
buildDebug('Resolving entries for federation build');
|
|
17
|
-
const entries = await resolveEntries({
|
|
18
|
-
cwd,
|
|
19
|
-
entry,
|
|
20
|
-
isApp,
|
|
21
|
-
isWorkbenchApp
|
|
22
|
-
});
|
|
23
|
-
buildDebug('Resolving vite config (federation)');
|
|
24
|
-
let viteConfig = await getViteConfig({
|
|
25
|
-
basePath,
|
|
26
|
-
cwd,
|
|
27
|
-
entries,
|
|
28
|
-
getEnvironmentVariables,
|
|
29
|
-
isApp,
|
|
30
|
-
isWorkbenchApp,
|
|
31
|
-
minify,
|
|
32
|
-
mode,
|
|
33
|
-
outputDir,
|
|
34
|
-
reactCompiler,
|
|
35
|
-
// Schema extraction is a build-time artifact, not a client-specific step,
|
|
36
|
-
// so a federated studio extracts its schema like the legacy studio build.
|
|
37
|
-
schemaExtraction,
|
|
38
|
-
services,
|
|
39
|
-
sourceMap,
|
|
40
|
-
views
|
|
41
|
-
});
|
|
42
|
-
// Apply the user's Vite config so plugins like `@vanilla-extract/vite-plugin`
|
|
43
|
-
// transform source files before the federation environment is bundled.
|
|
44
|
-
// `finalizeViteConfig` is intentionally skipped: the federation environment
|
|
45
|
-
// has its own entry and does not use `.sanity/runtime/app.js`.
|
|
46
|
-
if (extendViteConfig) {
|
|
47
|
-
viteConfig = await extendViteConfigWithUserConfig({
|
|
48
|
-
command: 'build',
|
|
49
|
-
mode
|
|
50
|
-
}, viteConfig, extendViteConfig);
|
|
51
|
-
}
|
|
52
|
-
buildDebug('Bundling federation environment');
|
|
53
|
-
const builder = await createBuilder(viteConfig);
|
|
54
|
-
await builder.buildApp();
|
|
55
|
-
buildDebug('Bundling complete');
|
|
56
|
-
// TODO: add stats here
|
|
57
|
-
return {
|
|
58
|
-
chunks: []
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
buildDebug('Writing Sanity runtime files');
|
|
62
|
-
const { entries } = await writeSanityRuntime({
|
|
63
|
-
appTitle,
|
|
64
|
-
basePath,
|
|
65
|
-
cwd,
|
|
66
|
-
entry,
|
|
67
|
-
isApp,
|
|
68
|
-
isWorkbenchApp,
|
|
69
|
-
reactStrictMode: false,
|
|
70
|
-
watch: false
|
|
71
|
-
});
|
|
72
|
-
function getEnvironmentVariables() {
|
|
73
|
-
return isApp ? getAppEnvironmentVariables({
|
|
74
|
-
jsonEncode: true,
|
|
75
|
-
prefix: 'process.env.'
|
|
76
|
-
}) : getStudioEnvironmentVariables({
|
|
77
|
-
jsonEncode: true,
|
|
78
|
-
prefix: 'process.env.'
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
buildDebug('Resolving vite config');
|
|
82
|
-
let viteConfig = await getViteConfig({
|
|
83
|
-
autoUpdates,
|
|
84
|
-
basePath,
|
|
85
|
-
cwd,
|
|
86
|
-
entries,
|
|
87
|
-
getEnvironmentVariables,
|
|
88
|
-
isApp,
|
|
89
|
-
isWorkbenchApp,
|
|
90
|
-
minify,
|
|
91
|
-
mode,
|
|
92
|
-
outputDir,
|
|
93
|
-
reactCompiler,
|
|
94
|
-
schemaExtraction,
|
|
95
|
-
sourceMap
|
|
96
|
-
});
|
|
97
|
-
if (extendViteConfig) {
|
|
98
|
-
const defaultViteConfig = viteConfig;
|
|
99
|
-
viteConfig = await extendViteConfigWithUserConfig({
|
|
100
|
-
command: 'build',
|
|
101
|
-
mode
|
|
102
|
-
}, viteConfig, extendViteConfig);
|
|
103
|
-
viteConfig = await finalizeViteConfig(viteConfig, defaultViteConfig);
|
|
104
|
-
}
|
|
105
|
-
const fromPath = path.join(cwd, 'static');
|
|
106
|
-
// Copy files placed in /static to the built /static
|
|
107
|
-
buildDebug(`Copying static files from ${fromPath} to output dir`);
|
|
108
|
-
const staticPath = path.join(outputDir, 'static');
|
|
109
|
-
await copyDir(fromPath, staticPath);
|
|
110
|
-
// Write favicons, not overwriting ones that already exist, to static folder
|
|
111
|
-
buildDebug('Writing favicons to output dir');
|
|
112
|
-
const faviconBasePath = `${basePath.replace(/\/+$/, '')}/static`;
|
|
113
|
-
await writeFavicons(faviconBasePath, staticPath);
|
|
114
|
-
buildDebug('Bundling using vite');
|
|
115
|
-
const bundle = await build(viteConfig);
|
|
116
|
-
buildDebug('Bundling complete');
|
|
117
|
-
// For typescript only - this shouldn't ever be the case given we're not watching
|
|
118
|
-
if (Array.isArray(bundle) || !('output' in bundle)) {
|
|
119
|
-
return {
|
|
120
|
-
chunks: []
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
const stats = [];
|
|
124
|
-
for (const chunk of bundle.output){
|
|
125
|
-
if (chunk.type !== 'chunk') {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
stats.push({
|
|
129
|
-
modules: Object.entries(chunk.modules).map(([rawFilePath, chunkModule])=>{
|
|
130
|
-
const filePath = rawFilePath.startsWith('\u0000') ? rawFilePath.slice('\u0000'.length) : rawFilePath;
|
|
131
|
-
return {
|
|
132
|
-
name: path.isAbsolute(filePath) ? path.relative(cwd, filePath) : filePath,
|
|
133
|
-
renderedLength: chunkModule.renderedLength
|
|
134
|
-
};
|
|
135
|
-
}),
|
|
136
|
-
name: chunk.name
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
chunks: stats
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
//# sourceMappingURL=buildStaticFiles.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/buildStaticFiles.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {\n type AutoUpdatesBuildConfig,\n buildDebug,\n copyDir,\n extendViteConfigWithUserConfig,\n finalizeViteConfig,\n getViteConfig,\n resolveEntries,\n writeFavicons,\n writeSanityRuntime,\n} from '@sanity/cli-build/_internal/build'\nimport {\n getAppEnvironmentVariables,\n getStudioEnvironmentVariables,\n} from '@sanity/cli-build/_internal/env'\nimport {type CliConfig, type UserViteConfig} from '@sanity/cli-core'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport {build, createBuilder} from 'vite'\n\nexport interface ChunkModule {\n name: string\n renderedLength: number\n}\n\nexport interface ChunkStats {\n modules: ChunkModule[]\n name: string\n}\n\ninterface StaticBuildOptions {\n basePath: string\n cwd: string\n outputDir: string\n\n appTitle?: string\n autoUpdates?: AutoUpdatesBuildConfig\n entry?: string\n isApp?: boolean\n /** Workbench app (opted in via `unstable_defineApp`) — drives the federation build. */\n isWorkbenchApp?: boolean\n minify?: boolean\n profile?: boolean\n reactCompiler?: ReactCompilerConfig\n schemaExtraction?: CliConfig['schemaExtraction']\n services?: DefineAppInput['services']\n sourceMap?: boolean\n views?: DefineAppInput['views']\n vite?: UserViteConfig\n}\n\n/**\n * Builds static files\n *\n * @internal\n */\nexport async function buildStaticFiles(\n options: StaticBuildOptions,\n): Promise<{chunks: ChunkStats[]}> {\n const {\n appTitle,\n autoUpdates,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n minify = true,\n outputDir,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap = false,\n views,\n vite: extendViteConfig,\n } = options\n\n const mode = 'production'\n\n /* Federation builds only produce the federation environment\n * (remote-entry, mf-manifest) — skip client-specific steps like\n * runtime generation, static file copies, and favicons.\n */\n if (isWorkbenchApp) {\n buildDebug('Resolving entries for federation build')\n const entries = await resolveEntries({cwd, entry, isApp, isWorkbenchApp})\n\n buildDebug('Resolving vite config (federation)')\n let viteConfig = await getViteConfig({\n basePath,\n cwd,\n entries,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n // Schema extraction is a build-time artifact, not a client-specific step,\n // so a federated studio extracts its schema like the legacy studio build.\n schemaExtraction,\n services,\n sourceMap,\n views,\n })\n\n // Apply the user's Vite config so plugins like `@vanilla-extract/vite-plugin`\n // transform source files before the federation environment is bundled.\n // `finalizeViteConfig` is intentionally skipped: the federation environment\n // has its own entry and does not use `.sanity/runtime/app.js`.\n if (extendViteConfig) {\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n }\n\n buildDebug('Bundling federation environment')\n const builder = await createBuilder(viteConfig)\n await builder.buildApp()\n buildDebug('Bundling complete')\n // TODO: add stats here\n return {chunks: []}\n }\n\n buildDebug('Writing Sanity runtime files')\n const {entries} = await writeSanityRuntime({\n appTitle,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n reactStrictMode: false,\n watch: false,\n })\n\n function getEnvironmentVariables() {\n return isApp\n ? getAppEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n : getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n }\n\n buildDebug('Resolving vite config')\n let viteConfig = await getViteConfig({\n autoUpdates,\n basePath,\n cwd,\n entries,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n schemaExtraction,\n sourceMap,\n })\n\n if (extendViteConfig) {\n const defaultViteConfig = viteConfig\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n viteConfig = await finalizeViteConfig(viteConfig, defaultViteConfig)\n }\n\n const fromPath = path.join(cwd, 'static')\n // Copy files placed in /static to the built /static\n buildDebug(`Copying static files from ${fromPath} to output dir`)\n const staticPath = path.join(outputDir, 'static')\n await copyDir(fromPath, staticPath)\n\n // Write favicons, not overwriting ones that already exist, to static folder\n buildDebug('Writing favicons to output dir')\n const faviconBasePath = `${basePath.replace(/\\/+$/, '')}/static`\n await writeFavicons(faviconBasePath, staticPath)\n\n buildDebug('Bundling using vite')\n const bundle = await build(viteConfig)\n buildDebug('Bundling complete')\n\n // For typescript only - this shouldn't ever be the case given we're not watching\n if (Array.isArray(bundle) || !('output' in bundle)) {\n return {chunks: []}\n }\n\n const stats: ChunkStats[] = []\n for (const chunk of bundle.output) {\n if (chunk.type !== 'chunk') {\n continue\n }\n\n stats.push({\n modules: Object.entries(chunk.modules).map(([rawFilePath, chunkModule]) => {\n const filePath = rawFilePath.startsWith('\\u0000')\n ? rawFilePath.slice('\\u0000'.length)\n : rawFilePath\n\n return {\n name: path.isAbsolute(filePath) ? path.relative(cwd, filePath) : filePath,\n renderedLength: chunkModule.renderedLength,\n }\n }),\n name: chunk.name,\n })\n }\n\n return {chunks: stats}\n}\n"],"names":["path","buildDebug","copyDir","extendViteConfigWithUserConfig","finalizeViteConfig","getViteConfig","resolveEntries","writeFavicons","writeSanityRuntime","getAppEnvironmentVariables","getStudioEnvironmentVariables","build","createBuilder","buildStaticFiles","options","appTitle","autoUpdates","basePath","cwd","entry","isApp","isWorkbenchApp","minify","outputDir","reactCompiler","schemaExtraction","services","sourceMap","views","vite","extendViteConfig","mode","entries","viteConfig","getEnvironmentVariables","command","builder","buildApp","chunks","reactStrictMode","watch","jsonEncode","prefix","defaultViteConfig","fromPath","join","staticPath","faviconBasePath","replace","bundle","Array","isArray","stats","chunk","output","type","push","modules","Object","map","rawFilePath","chunkModule","filePath","startsWith","slice","length","name","isAbsolute","relative","renderedLength"],"mappings":"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"}
|
package/dist/util/formatSize.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/formatSize.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\n/**\n * Formats bytes to kB\n *\n * @internal\n */\nexport function formatSize(bytes: number): string {\n return styleText('cyan', `${(bytes / 1024).toFixed(0)} kB`)\n}\n"],"names":["styleText","formatSize","bytes","toFixed"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC;;;;CAIC,GACD,OAAO,SAASC,WAAWC,KAAa;IACtC,OAAOF,UAAU,QAAQ,GAAG,AAACE,CAAAA,QAAQ,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;AAC5D"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { formatSize } from './formatSize.js';
|
|
2
|
-
export function formatModuleSizes(modules) {
|
|
3
|
-
const lines = [];
|
|
4
|
-
for (const mod of modules){
|
|
5
|
-
lines.push(` - ${formatModuleName(mod.name)} (${formatSize(mod.renderedLength)})`);
|
|
6
|
-
}
|
|
7
|
-
return lines.join('\n');
|
|
8
|
-
}
|
|
9
|
-
function formatModuleName(modName) {
|
|
10
|
-
const delimiter = '/node_modules/';
|
|
11
|
-
const nodeIndex = modName.lastIndexOf(delimiter);
|
|
12
|
-
return nodeIndex === -1 ? modName : modName.slice(nodeIndex + delimiter.length);
|
|
13
|
-
}
|
|
14
|
-
export function sortModulesBySize(chunks) {
|
|
15
|
-
return chunks.flatMap((chunk)=>chunk.modules).toSorted((modA, modB)=>modB.renderedLength - modA.renderedLength);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
//# sourceMappingURL=moduleFormatUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/moduleFormatUtils.ts"],"sourcesContent":["import {type ChunkModule, type ChunkStats} from '../actions/build/buildStaticFiles.js'\nimport {formatSize} from './formatSize.js'\n\nexport function formatModuleSizes(modules: ChunkModule[]): string {\n const lines: string[] = []\n for (const mod of modules) {\n lines.push(` - ${formatModuleName(mod.name)} (${formatSize(mod.renderedLength)})`)\n }\n\n return lines.join('\\n')\n}\n\nfunction formatModuleName(modName: string): string {\n const delimiter = '/node_modules/'\n const nodeIndex = modName.lastIndexOf(delimiter)\n return nodeIndex === -1 ? modName : modName.slice(nodeIndex + delimiter.length)\n}\n\nexport function sortModulesBySize(chunks: ChunkStats[]): ChunkModule[] {\n return chunks\n .flatMap((chunk) => chunk.modules)\n .toSorted((modA, modB) => modB.renderedLength - modA.renderedLength)\n}\n"],"names":["formatSize","formatModuleSizes","modules","lines","mod","push","formatModuleName","name","renderedLength","join","modName","delimiter","nodeIndex","lastIndexOf","slice","length","sortModulesBySize","chunks","flatMap","chunk","toSorted","modA","modB"],"mappings":"AACA,SAAQA,UAAU,QAAO,kBAAiB;AAE1C,OAAO,SAASC,kBAAkBC,OAAsB;IACtD,MAAMC,QAAkB,EAAE;IAC1B,KAAK,MAAMC,OAAOF,QAAS;QACzBC,MAAME,IAAI,CAAC,CAAC,GAAG,EAAEC,iBAAiBF,IAAIG,IAAI,EAAE,EAAE,EAAEP,WAAWI,IAAII,cAAc,EAAE,CAAC,CAAC;IACnF;IAEA,OAAOL,MAAMM,IAAI,CAAC;AACpB;AAEA,SAASH,iBAAiBI,OAAe;IACvC,MAAMC,YAAY;IAClB,MAAMC,YAAYF,QAAQG,WAAW,CAACF;IACtC,OAAOC,cAAc,CAAC,IAAIF,UAAUA,QAAQI,KAAK,CAACF,YAAYD,UAAUI,MAAM;AAChF;AAEA,OAAO,SAASC,kBAAkBC,MAAoB;IACpD,OAAOA,OACJC,OAAO,CAAC,CAACC,QAAUA,MAAMjB,OAAO,EAChCkB,QAAQ,CAAC,CAACC,MAAMC,OAASA,KAAKd,cAAc,GAAGa,KAAKb,cAAc;AACvE"}
|