@sanity/cli 7.11.0 → 7.12.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n buildExposes,\n deployConfig,\n deployCoreApp as deployWorkbenchCoreApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n summarizeConfig,\n} from '@sanity/workbench-cli/deploy'\nimport {pack} from 'tar-fs'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '../manifest/extractCoreAppManifest.js'\nimport {type CoreAppManifest} from '../manifest/types.js'\nimport {createUserApplication, generateAppSlug} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportExposes} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A singleton (the Media Library) persists its config instead of hosting an\n // application; anything that exposes a view or service still ships one.\n const deploySingletonConfig = workbench?.deploySingletonConfig ?? false\n const deployApplication = !workbench || workbench.hasInterfaces\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deploySingletonConfig) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n slug: workbench.slug,\n title: appTitle,\n })\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({isWorkbenchApp: workbench !== null, reporter, sourceDir})\n\n // Workbench apps ship their icon straight to Brett (below) and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let config: string | undefined\n const configAppType = workbench?.config?.appType\n if (deploySingletonConfig && organizationId && workbench?.config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n config = summarizeConfig(workbench.config)\n reporter.report(\n installationId\n ? {config, message: config, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution: 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Report the exposes deploying with the application, both modes.\n const exposes = deployApplication && workbench ? reportExposes(reporter, workbench) : []\n\n // Surface the app's explicit singleton flag when set, both modes.\n if (deployApplication && workbench?.isSingleton !== undefined) {\n reporter.report({\n isSingleton: workbench.isSingleton,\n message: `Singleton: ${workbench.isSingleton}`,\n status: 'pass',\n })\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n if (installationId && version) {\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(config ? {config} : {}),\n installationId,\n target: null,\n }\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // Workbench apps deploy to Brett; plain coreApps use user-applications.\n if (workbench && organizationId) {\n const appId = getAppId(cliConfig)\n const slug = workbench.slug ?? generateAppSlug()\n const {applicationId} = await deployWorkbenchCoreApp({\n appId,\n icon: workbench.icon ? await readIconFromPath(workDir, workbench.icon) : undefined,\n interfaces: buildExposes(workbench, {\n appName: workbench.name,\n appTitle,\n exposesAppView: workbench.entry !== undefined,\n version,\n }),\n isAutoUpdating,\n isSingleton: workbench.isSingleton,\n organizationId,\n slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: !appId,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(exposes.length > 0 ? {exposes} : {}),\n ...(workbench.isSingleton === undefined ? {} : {isSingleton: workbench.isSingleton}),\n target: {\n action: appId ? 'update' : 'create',\n applicationId,\n // A redeploy ignores the slug, so only a create reports the one it used.\n ...(appId ? {} : {slug}),\n title: appTitle,\n url,\n },\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n target: {\n action: appCreated ? 'create' : 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url: getCoreAppUrl(application.organizationId, application.id),\n },\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","exitCodes","getErrorMessage","getCoreAppUrl","spinner","buildExposes","deployConfig","deployCoreApp","deployWorkbenchCoreApp","getApplicationUrl","getWorkbench","resolveInstallationId","summarizeConfig","pack","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","createUserApplication","generateAppSlug","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportExposes","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","dryRun","deploySingletonConfig","deployApplication","hasInterfaces","appTitle","title","trim","name","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","isAutoUpdating","version","moduleName","application","appCreated","external","isWorkbenchApp","slug","created","resolveAppApplication","build","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","undefined","successMessage","manifest","installationId","config","configAppType","appType","exposes","isSingleton","applicationType","applicationVersion","target","applicationId","icon","interfaces","appName","exposesAppView","entry","visibility","url","id","logAppDeployed","length","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","entries","pipe","isApp","error","clear","named"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n buildExposes,\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n summarizeConfig,\n} from '@sanity/workbench-cli/deploy'\nimport {pack} from 'tar-fs'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '../manifest/extractCoreAppManifest.js'\nimport {type CoreAppManifest} from '../manifest/types.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportExposes} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A singleton (the Media Library) persists its config instead of hosting an\n // application; anything that exposes a view or service still ships one.\n const deploySingletonConfig = workbench?.deploySingletonConfig ?? false\n const deployApplication = !workbench || workbench.hasInterfaces\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deploySingletonConfig) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n slug: workbench.slug,\n title: appTitle,\n })\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n ;({applicationId, rollback: rollbackApp} = await createCoreApp({\n isSingleton: workbench.isSingleton,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n }))\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({isWorkbenchApp: workbench !== null, reporter, sourceDir})\n\n // Workbench apps ship their icon straight to Brett (below) and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let config: string | undefined\n const configAppType = workbench?.config?.appType\n if (deploySingletonConfig && organizationId && workbench?.config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n config = summarizeConfig(workbench.config)\n reporter.report(\n installationId\n ? {config, message: config, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Report the exposes deploying with the application, both modes.\n const exposes = deployApplication && workbench ? reportExposes(reporter, workbench) : []\n\n // Surface the app's explicit singleton flag when set, both modes.\n if (deployApplication && workbench?.isSingleton !== undefined) {\n reporter.report({\n isSingleton: workbench.isSingleton,\n message: `Singleton: ${workbench.isSingleton}`,\n status: 'pass',\n })\n }\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(config ? {config} : {}),\n installationId,\n target: null,\n }\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n applicationId,\n icon: appIcon,\n interfaces: buildExposes(workbench, {\n appName: workbench.name,\n appTitle,\n exposesAppView: workbench.entry !== undefined,\n version,\n }),\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(exposes.length > 0 ? {exposes} : {}),\n ...(workbench.isSingleton === undefined ? {} : {isSingleton: workbench.isSingleton}),\n target: {\n action: applicationCreated ? 'create' : 'update',\n applicationId,\n // A redeploy targets an existing app; only a create reports the slug.\n ...(applicationCreated ? {slug: workbench.slug} : {}),\n title: appTitle,\n url,\n },\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n target: {\n action: appCreated ? 'create' : 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url: getCoreAppUrl(application.organizationId, application.id),\n },\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","exitCodes","getErrorMessage","getCoreAppUrl","spinner","buildExposes","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","summarizeConfig","pack","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportExposes","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","dryRun","deploySingletonConfig","deployApplication","hasInterfaces","appTitle","title","trim","name","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","isAutoUpdating","version","moduleName","application","appCreated","external","isWorkbenchApp","slug","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","rollback","isSingleton","visibility","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","config","configAppType","appType","exposes","deployApplicationConfig","applicationType","applicationVersion","target","interfaces","appName","exposesAppView","entry","onDeployed","url","id","logAppDeployed","length","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","entries","pipe","isApp","error","clear","named"],"mappings":"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"}
@@ -293,7 +293,7 @@ export function describeAppTargetError(err, organizationId) {
293
293
  const { title } = options;
294
294
  const resolve = options.isWorkbenchApp ? resolveWorkbenchStudio({
295
295
  appId: options.appId,
296
- studioHost: options.studioHost
296
+ slug: options.slug
297
297
  }) : resolveStudioDeployTarget(options);
298
298
  // Workbench studios always deploy to Sanity hosting, never an external URL.
299
299
  const isExternal = options.isWorkbenchApp ? false : options.isExternal;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployChecks.ts"],"sourcesContent":["import {type CliConfig, exitCodes, getLocalPackageVersion} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {checkBuiltOutput, type DeployedExpose} from '@sanity/workbench-cli/deploy'\n\nimport {resolveAppIdIssue} from '../../util/appId.js'\nimport {type Check, type CheckReporter, runStep} from '../../util/checks.js'\nimport {APP_ID_NOT_FOUND_IN_ORGANIZATION} from '../../util/errorMessages.js'\nimport {\n getAutoUpdateIssueMessage,\n getAutoUpdateMigrationHint,\n resolveAutoUpdates,\n} from '../build/shouldAutoUpdate.js'\nimport {checkDir} from './checkDir.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type AppDeployTargetResolution,\n resolveAppDeployTarget,\n resolveStudioDeployTarget,\n resolveWorkbenchApp,\n resolveWorkbenchStudio,\n type StudioDeployTargetResolution,\n} from './resolveDeployTarget.js'\nimport {type DeployFlags} from './types.js'\n\n/**\n * Where a deploy resolves to, computed once from the deploy-target verdict. The\n * dry-run report and its JSON both read this, so the human and machine outputs\n * can't drift.\n */\nexport interface DeployTarget {\n /** Whether the deploy creates a new application/studio or updates an existing one. */\n action: 'create' | 'update'\n /** The application the deploy targets; `null` when a deploy would create one. */\n applicationId: string | null\n /** The application's title; `null` when it has none (or isn't created yet). */\n title: string | null\n /** Where the deployed studio/app is reachable; `null` when it can't be resolved yet. */\n url: string | null\n\n /**\n * Slug the deploy creates the application at. Omitted on redeploys, and in a\n * dry run when no slug is configured (it's generated on deploy).\n */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** Set on the config check with its summary both reporters read. */\n config?: string\n /** Set on the exposes check with the workbench exposes both reporters read. */\n exposes?: DeployedExpose[]\n /** Set on the singleton check when the app declares the flag explicitly. */\n isSingleton?: boolean\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\n /** Set on the package-version check with the version both reporters read. */\n version?: string\n}\n\nexport type DeployCheckReporter = CheckReporter<DeployCheck>\n\nexport async function checkPackageVersion(\n reporter: DeployCheckReporter,\n {moduleName, workDir}: {moduleName: string; workDir: string},\n): Promise<string | null> {\n const version = await getLocalPackageVersion(moduleName, workDir)\n reporter.report(\n version\n ? {message: `Using ${moduleName} ${version}`, status: 'pass', version}\n : {\n message: `Failed to find installed ${moduleName} version`,\n solution: `Install ${moduleName} in this project`,\n status: 'fail',\n },\n )\n return version\n}\n\nexport function checkAutoUpdates(\n reporter: DeployCheckReporter,\n {cliConfig, flags}: {cliConfig: CliConfig; flags: DeployFlags},\n): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n if (issue) {\n reporter.report({\n message: getAutoUpdateIssueMessage(issue),\n // A config conflict makes a real deploy refuse to run; deprecations only warn\n status: issue.type === 'conflicting-config' ? 'fail' : 'warn',\n })\n\n // The deprecated top-level config also gets the styled migration edit, the\n // same second warning the build/dev path prints through shouldAutoUpdate.\n if (issue.type === 'deprecated-config') {\n reporter.report({\n message: getAutoUpdateMigrationHint(cliConfig.autoUpdates),\n status: 'warn',\n })\n }\n }\n\n return enabled\n}\n\n/**\n * The dry-run form of the `app.id` config check a real deploy runs in\n * `findUserApplication`: a conflict fails (both `app.id` and `deployment.appId`\n * set), the deprecated config alone warns.\n */\nexport function checkAppId(\n reporter: DeployCheckReporter,\n {cliConfig}: {cliConfig: CliConfig},\n): void {\n const issue = resolveAppIdIssue(cliConfig)\n if (issue === 'conflicting-config') {\n reporter.report({\n message: 'Both `app.id` (deprecated) and `deployment.appId` are set',\n solution: 'Remove `app.id` from sanity.cli.ts',\n status: 'fail',\n })\n } else if (issue === 'deprecated-config') {\n reporter.report({\n message: 'The `app.id` config is deprecated',\n solution: 'Move it to `deployment.appId` in sanity.cli.ts',\n status: 'warn',\n })\n }\n}\n\nexport async function checkBuild(\n reporter: DeployCheckReporter,\n {\n build,\n skipReason,\n successMessage,\n }: {build: () => Promise<void>; skipReason: string | undefined; successMessage: string},\n): Promise<void> {\n if (skipReason) {\n reporter.report({message: skipReason, status: 'skip'})\n return\n }\n\n await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Build failed: ${getErrorMessage(err)}`,\n name: 'build',\n solution: 'Fix the build error above, then retry',\n work: async () => {\n await build()\n reporter.report({message: successMessage, status: 'pass'})\n },\n })\n}\n\n/**\n * The deploy directory must exist and hold the right build output: a federation\n * remote for a workbench app, an `index.html` SPA otherwise.\n */\nexport async function verifyOutputDir({\n isWorkbenchApp,\n reporter,\n sourceDir,\n}: {\n isWorkbenchApp: boolean\n reporter: DeployCheckReporter\n sourceDir: string\n}): Promise<void> {\n const spin = spinner('Verifying local content...').start()\n const verifyBuild = isWorkbenchApp ? checkBuiltOutput : checkDir\n try {\n await verifyBuild(sourceDir)\n spin.succeed()\n } catch (err) {\n spin.fail()\n deployDebug('Error checking directory', err)\n reporter.report({\n message: getErrorMessage(err),\n solution: 'Run the build first, or check the output directory',\n status: 'fail',\n })\n }\n}\n\n/**\n * The single diagnosis for each app deploy-target verdict, shared by the\n * dry-run report and the real deploy's unattended error paths so message,\n * fix, and exit code can't drift between the two.\n */\nexport function describeAppTarget(\n resolution: AppDeployTargetResolution,\n {slug, title}: {slug?: string; title?: string} = {},\n): DeployCheck {\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {application} = resolution\n const title = application.title ?? application.appHost\n const url = application.url ?? getCoreAppUrl(application.organizationId, application.id)\n return {\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url,\n },\n }\n }\n case 'invalid': {\n return {\n message: APP_ID_NOT_FOUND_IN_ORGANIZATION,\n solution: 'Check `deployment.appId` matches an app in your organization',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No \\`deployment.appId\\` configured (${resolution.existing.length} existing ${resolution.existing.length === 1 ? 'application' : 'applications'} to choose from)`,\n solution: 'Add `deployment.appId` to sanity.cli.ts',\n status: 'fail',\n }\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${slug ? ` with slug \"${slug}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n applicationId: null,\n ...(slug ? {slug} : {}),\n title,\n url: null,\n },\n }\n }\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: 'No application to deploy to — creating one needs a title',\n solution:\n 'Pass `--title \"<name>\"` or set `app.title` in sanity.cli.ts to create one, or set `deployment.appId` to deploy to an existing app',\n status: 'fail',\n }\n }\n }\n}\n\nexport function describeAppTargetError(err: unknown, organizationId: string | undefined): string {\n return (err as {statusCode?: number})?.statusCode === 403\n ? `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\"). Verify the organization ID, or ask your organization’s admin for access.`\n : `Failed to resolve deploy target: ${getErrorMessage(err)}`\n}\n\n/**\n * Reports the app deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkAppTarget(\n reporter: DeployCheckReporter,\n options:\n | {appId: string | undefined; isWorkbenchApp: true; slug?: string; title?: string}\n | {\n appId: string | undefined\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n },\n): Promise<DeployTarget | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const check = describeAppTarget(await resolveWorkbenchApp({appId}), {slug, title})\n reporter.report(check)\n return check.target ?? null\n },\n })\n }\n\n const {appId, organizationId} = options\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => describeAppTargetError(err, organizationId),\n name: 'target',\n work: async () => {\n const check = describeAppTarget(await resolveAppDeployTarget({appId, organizationId}), {\n title,\n })\n reporter.report(check)\n return check.target ?? null\n },\n })\n}\n\n/** Same contract as {@link describeAppTarget}, for the studio verdicts. */\nexport function describeStudioTarget(\n resolution: StudioDeployTargetResolution,\n {isExternal, isWorkbench, title}: {isExternal: boolean; isWorkbench?: boolean; title?: string},\n): DeployCheck {\n const studioUrl = (host: string) => (isExternal ? host : `https://${host}.sanity.studio`)\n\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const url = resolution.application.url ?? studioUrl(resolution.application.appHost)\n return {\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n applicationId: resolution.application.id,\n title: resolution.application.title ?? null,\n url,\n },\n }\n }\n case 'invalid': {\n return {\n // A bad host is a usage error; other invalid targets exit 1\n exitCode: resolution.reason === 'invalid-host' ? exitCodes.USAGE_ERROR : 1,\n message: resolution.message,\n solution: 'Check `studioHost` and `deployment.appId` in sanity.cli.ts',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: isExternal ? 'No external studio URL configured' : 'No studio hostname configured',\n solution: isExternal\n ? 'Set `studioHost` in sanity.cli.ts, or pass the full URL with --url'\n : 'Set `studioHost` in sanity.cli.ts, or pass a hostname with --url',\n status: 'fail',\n }\n }\n case 'would-create': {\n // A workbench studio's URL needs the application id, which only exists after the create.\n const url = isWorkbench ? null : studioUrl(resolution.appHost)\n const titled = title ? ` titled \"${title}\"` : ''\n return {\n message: isExternal\n ? `Would register external studio at ${resolution.appHost}${titled}`\n : `Would create studio hostname ${url ?? resolution.appHost}${titled} (name availability is checked on deploy)`,\n status: 'pass',\n // `title || null`, not `?? null`, so target.title tracks the same\n // truthiness the message's `titled` suffix uses (an empty title is no title)\n target: {action: 'create', applicationId: null, title: title || null, url},\n }\n }\n }\n}\n\n/**\n * Reports the studio deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkStudioTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n isExternal: boolean\n isWorkbenchApp?: false\n projectId: string | undefined\n studioHost: string | undefined\n title: string | undefined\n urlFlag: string | undefined\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n studioHost: string | undefined\n title?: string\n },\n): Promise<DeployTarget | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio({appId: options.appId, studioHost: options.studioHost})\n : resolveStudioDeployTarget(options)\n // Workbench studios always deploy to Sanity hosting, never an external URL.\n const isExternal = options.isWorkbenchApp ? false : options.isExternal\n\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Failed to resolve deploy target: ${getErrorMessage(err)}`,\n name: 'target',\n work: async () => {\n const check = describeStudioTarget(await resolve, {\n isExternal,\n isWorkbench: !!options.isWorkbenchApp,\n title,\n })\n reporter.report(check)\n return check.target ?? null\n },\n })\n}\n"],"names":["exitCodes","getLocalPackageVersion","getErrorMessage","getCoreAppUrl","spinner","checkBuiltOutput","resolveAppIdIssue","runStep","APP_ID_NOT_FOUND_IN_ORGANIZATION","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","resolveAutoUpdates","checkDir","deployDebug","resolveAppDeployTarget","resolveStudioDeployTarget","resolveWorkbenchApp","resolveWorkbenchStudio","checkPackageVersion","reporter","moduleName","workDir","version","report","message","status","solution","checkAutoUpdates","cliConfig","flags","enabled","issue","type","autoUpdates","checkAppId","checkBuild","build","skipReason","successMessage","debug","formatError","err","name","work","verifyOutputDir","isWorkbenchApp","sourceDir","spin","start","verifyBuild","succeed","fail","describeAppTarget","resolution","slug","title","application","appHost","url","organizationId","id","target","action","applicationId","exitCode","USAGE_ERROR","existing","length","describeAppTargetError","statusCode","checkAppTarget","options","appId","check","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","titled","checkStudioTarget","resolve","studioHost"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployChecks.ts"],"sourcesContent":["import {type CliConfig, exitCodes, getLocalPackageVersion} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {checkBuiltOutput, type DeployedExpose} from '@sanity/workbench-cli/deploy'\n\nimport {resolveAppIdIssue} from '../../util/appId.js'\nimport {type Check, type CheckReporter, runStep} from '../../util/checks.js'\nimport {APP_ID_NOT_FOUND_IN_ORGANIZATION} from '../../util/errorMessages.js'\nimport {\n getAutoUpdateIssueMessage,\n getAutoUpdateMigrationHint,\n resolveAutoUpdates,\n} from '../build/shouldAutoUpdate.js'\nimport {checkDir} from './checkDir.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type AppDeployTargetResolution,\n resolveAppDeployTarget,\n resolveStudioDeployTarget,\n resolveWorkbenchApp,\n resolveWorkbenchStudio,\n type StudioDeployTargetResolution,\n} from './resolveDeployTarget.js'\nimport {type DeployFlags} from './types.js'\n\n/**\n * Where a deploy resolves to, computed once from the deploy-target verdict. The\n * dry-run report and its JSON both read this, so the human and machine outputs\n * can't drift.\n */\nexport interface DeployTarget {\n /** Whether the deploy creates a new application/studio or updates an existing one. */\n action: 'create' | 'update'\n /** The application the deploy targets; `null` when a deploy would create one. */\n applicationId: string | null\n /** The application's title; `null` when it has none (or isn't created yet). */\n title: string | null\n /** Where the deployed studio/app is reachable; `null` when it can't be resolved yet. */\n url: string | null\n\n /**\n * Slug the deploy creates the application at. Omitted on redeploys, and in a\n * dry run when no slug is configured (it's generated on deploy).\n */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** Set on the config check with its summary both reporters read. */\n config?: string\n /** Set on the exposes check with the workbench exposes both reporters read. */\n exposes?: DeployedExpose[]\n /** Set on the singleton check when the app declares the flag explicitly. */\n isSingleton?: boolean\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\n /** Set on the package-version check with the version both reporters read. */\n version?: string\n}\n\nexport type DeployCheckReporter = CheckReporter<DeployCheck>\n\nexport async function checkPackageVersion(\n reporter: DeployCheckReporter,\n {moduleName, workDir}: {moduleName: string; workDir: string},\n): Promise<string | null> {\n const version = await getLocalPackageVersion(moduleName, workDir)\n reporter.report(\n version\n ? {message: `Using ${moduleName} ${version}`, status: 'pass', version}\n : {\n message: `Failed to find installed ${moduleName} version`,\n solution: `Install ${moduleName} in this project`,\n status: 'fail',\n },\n )\n return version\n}\n\nexport function checkAutoUpdates(\n reporter: DeployCheckReporter,\n {cliConfig, flags}: {cliConfig: CliConfig; flags: DeployFlags},\n): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n if (issue) {\n reporter.report({\n message: getAutoUpdateIssueMessage(issue),\n // A config conflict makes a real deploy refuse to run; deprecations only warn\n status: issue.type === 'conflicting-config' ? 'fail' : 'warn',\n })\n\n // The deprecated top-level config also gets the styled migration edit, the\n // same second warning the build/dev path prints through shouldAutoUpdate.\n if (issue.type === 'deprecated-config') {\n reporter.report({\n message: getAutoUpdateMigrationHint(cliConfig.autoUpdates),\n status: 'warn',\n })\n }\n }\n\n return enabled\n}\n\n/**\n * The dry-run form of the `app.id` config check a real deploy runs in\n * `findUserApplication`: a conflict fails (both `app.id` and `deployment.appId`\n * set), the deprecated config alone warns.\n */\nexport function checkAppId(\n reporter: DeployCheckReporter,\n {cliConfig}: {cliConfig: CliConfig},\n): void {\n const issue = resolveAppIdIssue(cliConfig)\n if (issue === 'conflicting-config') {\n reporter.report({\n message: 'Both `app.id` (deprecated) and `deployment.appId` are set',\n solution: 'Remove `app.id` from sanity.cli.ts',\n status: 'fail',\n })\n } else if (issue === 'deprecated-config') {\n reporter.report({\n message: 'The `app.id` config is deprecated',\n solution: 'Move it to `deployment.appId` in sanity.cli.ts',\n status: 'warn',\n })\n }\n}\n\nexport async function checkBuild(\n reporter: DeployCheckReporter,\n {\n build,\n skipReason,\n successMessage,\n }: {build: () => Promise<void>; skipReason: string | undefined; successMessage: string},\n): Promise<void> {\n if (skipReason) {\n reporter.report({message: skipReason, status: 'skip'})\n return\n }\n\n await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Build failed: ${getErrorMessage(err)}`,\n name: 'build',\n solution: 'Fix the build error above, then retry',\n work: async () => {\n await build()\n reporter.report({message: successMessage, status: 'pass'})\n },\n })\n}\n\n/**\n * The deploy directory must exist and hold the right build output: a federation\n * remote for a workbench app, an `index.html` SPA otherwise.\n */\nexport async function verifyOutputDir({\n isWorkbenchApp,\n reporter,\n sourceDir,\n}: {\n isWorkbenchApp: boolean\n reporter: DeployCheckReporter\n sourceDir: string\n}): Promise<void> {\n const spin = spinner('Verifying local content...').start()\n const verifyBuild = isWorkbenchApp ? checkBuiltOutput : checkDir\n try {\n await verifyBuild(sourceDir)\n spin.succeed()\n } catch (err) {\n spin.fail()\n deployDebug('Error checking directory', err)\n reporter.report({\n message: getErrorMessage(err),\n solution: 'Run the build first, or check the output directory',\n status: 'fail',\n })\n }\n}\n\n/**\n * The single diagnosis for each app deploy-target verdict, shared by the\n * dry-run report and the real deploy's unattended error paths so message,\n * fix, and exit code can't drift between the two.\n */\nexport function describeAppTarget(\n resolution: AppDeployTargetResolution,\n {slug, title}: {slug?: string; title?: string} = {},\n): DeployCheck {\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {application} = resolution\n const title = application.title ?? application.appHost\n const url = application.url ?? getCoreAppUrl(application.organizationId, application.id)\n return {\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url,\n },\n }\n }\n case 'invalid': {\n return {\n message: APP_ID_NOT_FOUND_IN_ORGANIZATION,\n solution: 'Check `deployment.appId` matches an app in your organization',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No \\`deployment.appId\\` configured (${resolution.existing.length} existing ${resolution.existing.length === 1 ? 'application' : 'applications'} to choose from)`,\n solution: 'Add `deployment.appId` to sanity.cli.ts',\n status: 'fail',\n }\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${slug ? ` with slug \"${slug}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n applicationId: null,\n ...(slug ? {slug} : {}),\n title,\n url: null,\n },\n }\n }\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: 'No application to deploy to — creating one needs a title',\n solution:\n 'Pass `--title \"<name>\"` or set `app.title` in sanity.cli.ts to create one, or set `deployment.appId` to deploy to an existing app',\n status: 'fail',\n }\n }\n }\n}\n\nexport function describeAppTargetError(err: unknown, organizationId: string | undefined): string {\n return (err as {statusCode?: number})?.statusCode === 403\n ? `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\"). Verify the organization ID, or ask your organization’s admin for access.`\n : `Failed to resolve deploy target: ${getErrorMessage(err)}`\n}\n\n/**\n * Reports the app deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkAppTarget(\n reporter: DeployCheckReporter,\n options:\n | {appId: string | undefined; isWorkbenchApp: true; slug?: string; title?: string}\n | {\n appId: string | undefined\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n },\n): Promise<DeployTarget | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const check = describeAppTarget(await resolveWorkbenchApp({appId}), {slug, title})\n reporter.report(check)\n return check.target ?? null\n },\n })\n }\n\n const {appId, organizationId} = options\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => describeAppTargetError(err, organizationId),\n name: 'target',\n work: async () => {\n const check = describeAppTarget(await resolveAppDeployTarget({appId, organizationId}), {\n title,\n })\n reporter.report(check)\n return check.target ?? null\n },\n })\n}\n\n/** Same contract as {@link describeAppTarget}, for the studio verdicts. */\nexport function describeStudioTarget(\n resolution: StudioDeployTargetResolution,\n {isExternal, isWorkbench, title}: {isExternal: boolean; isWorkbench?: boolean; title?: string},\n): DeployCheck {\n const studioUrl = (host: string) => (isExternal ? host : `https://${host}.sanity.studio`)\n\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const url = resolution.application.url ?? studioUrl(resolution.application.appHost)\n return {\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n applicationId: resolution.application.id,\n title: resolution.application.title ?? null,\n url,\n },\n }\n }\n case 'invalid': {\n return {\n // A bad host is a usage error; other invalid targets exit 1\n exitCode: resolution.reason === 'invalid-host' ? exitCodes.USAGE_ERROR : 1,\n message: resolution.message,\n solution: 'Check `studioHost` and `deployment.appId` in sanity.cli.ts',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: isExternal ? 'No external studio URL configured' : 'No studio hostname configured',\n solution: isExternal\n ? 'Set `studioHost` in sanity.cli.ts, or pass the full URL with --url'\n : 'Set `studioHost` in sanity.cli.ts, or pass a hostname with --url',\n status: 'fail',\n }\n }\n case 'would-create': {\n // A workbench studio's URL needs the application id, which only exists after the create.\n const url = isWorkbench ? null : studioUrl(resolution.appHost)\n const titled = title ? ` titled \"${title}\"` : ''\n return {\n message: isExternal\n ? `Would register external studio at ${resolution.appHost}${titled}`\n : `Would create studio hostname ${url ?? resolution.appHost}${titled} (name availability is checked on deploy)`,\n status: 'pass',\n // `title || null`, not `?? null`, so target.title tracks the same\n // truthiness the message's `titled` suffix uses (an empty title is no title)\n target: {action: 'create', applicationId: null, title: title || null, url},\n }\n }\n }\n}\n\n/**\n * Reports the studio deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkStudioTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n isExternal: boolean\n isWorkbenchApp?: false\n projectId: string | undefined\n studioHost: string | undefined\n title: string | undefined\n urlFlag: string | undefined\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n slug: string\n title?: string\n },\n): Promise<DeployTarget | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio({appId: options.appId, slug: options.slug})\n : resolveStudioDeployTarget(options)\n // Workbench studios always deploy to Sanity hosting, never an external URL.\n const isExternal = options.isWorkbenchApp ? false : options.isExternal\n\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Failed to resolve deploy target: ${getErrorMessage(err)}`,\n name: 'target',\n work: async () => {\n const check = describeStudioTarget(await resolve, {\n isExternal,\n isWorkbench: !!options.isWorkbenchApp,\n title,\n })\n reporter.report(check)\n return check.target ?? null\n },\n })\n}\n"],"names":["exitCodes","getLocalPackageVersion","getErrorMessage","getCoreAppUrl","spinner","checkBuiltOutput","resolveAppIdIssue","runStep","APP_ID_NOT_FOUND_IN_ORGANIZATION","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","resolveAutoUpdates","checkDir","deployDebug","resolveAppDeployTarget","resolveStudioDeployTarget","resolveWorkbenchApp","resolveWorkbenchStudio","checkPackageVersion","reporter","moduleName","workDir","version","report","message","status","solution","checkAutoUpdates","cliConfig","flags","enabled","issue","type","autoUpdates","checkAppId","checkBuild","build","skipReason","successMessage","debug","formatError","err","name","work","verifyOutputDir","isWorkbenchApp","sourceDir","spin","start","verifyBuild","succeed","fail","describeAppTarget","resolution","slug","title","application","appHost","url","organizationId","id","target","action","applicationId","exitCode","USAGE_ERROR","existing","length","describeAppTargetError","statusCode","checkAppTarget","options","appId","check","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","titled","checkStudioTarget","resolve"],"mappings":"AAAA,SAAwBA,SAAS,EAAEC,sBAAsB,QAAO,mBAAkB;AAClF,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,aAAa,QAAO,wBAAuB;AACnD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,gBAAgB,QAA4B,+BAA8B;AAElF,SAAQC,iBAAiB,QAAO,sBAAqB;AACrD,SAAwCC,OAAO,QAAO,uBAAsB;AAC5E,SAAQC,gCAAgC,QAAO,8BAA6B;AAC5E,SACEC,yBAAyB,EACzBC,0BAA0B,EAC1BC,kBAAkB,QACb,+BAA8B;AACrC,SAAQC,QAAQ,QAAO,gBAAe;AACtC,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAEEC,sBAAsB,EACtBC,yBAAyB,EACzBC,mBAAmB,EACnBC,sBAAsB,QAEjB,2BAA0B;AAwCjC,OAAO,eAAeC,oBACpBC,QAA6B,EAC7B,EAACC,UAAU,EAAEC,OAAO,EAAwC;IAE5D,MAAMC,UAAU,MAAMrB,uBAAuBmB,YAAYC;IACzDF,SAASI,MAAM,CACbD,UACI;QAACE,SAAS,CAAC,MAAM,EAAEJ,WAAW,CAAC,EAAEE,SAAS;QAAEG,QAAQ;QAAQH;IAAO,IACnE;QACEE,SAAS,CAAC,yBAAyB,EAAEJ,WAAW,QAAQ,CAAC;QACzDM,UAAU,CAAC,QAAQ,EAAEN,WAAW,gBAAgB,CAAC;QACjDK,QAAQ;IACV;IAEN,OAAOH;AACT;AAEA,OAAO,SAASK,iBACdR,QAA6B,EAC7B,EAACS,SAAS,EAAEC,KAAK,EAA6C;IAE9D,MAAM,EAACC,OAAO,EAAEC,KAAK,EAAC,GAAGpB,mBAAmB;QAACiB;QAAWC;IAAK;IAE7D,IAAIE,OAAO;QACTZ,SAASI,MAAM,CAAC;YACdC,SAASf,0BAA0BsB;YACnC,8EAA8E;YAC9EN,QAAQM,MAAMC,IAAI,KAAK,uBAAuB,SAAS;QACzD;QAEA,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAID,MAAMC,IAAI,KAAK,qBAAqB;YACtCb,SAASI,MAAM,CAAC;gBACdC,SAASd,2BAA2BkB,UAAUK,WAAW;gBACzDR,QAAQ;YACV;QACF;IACF;IAEA,OAAOK;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASI,WACdf,QAA6B,EAC7B,EAACS,SAAS,EAAyB;IAEnC,MAAMG,QAAQzB,kBAAkBsB;IAChC,IAAIG,UAAU,sBAAsB;QAClCZ,SAASI,MAAM,CAAC;YACdC,SAAS;YACTE,UAAU;YACVD,QAAQ;QACV;IACF,OAAO,IAAIM,UAAU,qBAAqB;QACxCZ,SAASI,MAAM,CAAC;YACdC,SAAS;YACTE,UAAU;YACVD,QAAQ;QACV;IACF;AACF;AAEA,OAAO,eAAeU,WACpBhB,QAA6B,EAC7B,EACEiB,KAAK,EACLC,UAAU,EACVC,cAAc,EACuE;IAEvF,IAAID,YAAY;QACdlB,SAASI,MAAM,CAAC;YAACC,SAASa;YAAYZ,QAAQ;QAAM;QACpD;IACF;IAEA,MAAMlB,QAAQY,UAAU;QACtBoB,OAAO1B;QACP2B,aAAa,CAACC,MAAQ,CAAC,cAAc,EAAEvC,gBAAgBuC,MAAM;QAC7DC,MAAM;QACNhB,UAAU;QACViB,MAAM;YACJ,MAAMP;YACNjB,SAASI,MAAM,CAAC;gBAACC,SAASc;gBAAgBb,QAAQ;YAAM;QAC1D;IACF;AACF;AAEA;;;CAGC,GACD,OAAO,eAAemB,gBAAgB,EACpCC,cAAc,EACd1B,QAAQ,EACR2B,SAAS,EAKV;IACC,MAAMC,OAAO3C,QAAQ,8BAA8B4C,KAAK;IACxD,MAAMC,cAAcJ,iBAAiBxC,mBAAmBO;IACxD,IAAI;QACF,MAAMqC,YAAYH;QAClBC,KAAKG,OAAO;IACd,EAAE,OAAOT,KAAK;QACZM,KAAKI,IAAI;QACTtC,YAAY,4BAA4B4B;QACxCtB,SAASI,MAAM,CAAC;YACdC,SAAStB,gBAAgBuC;YACzBf,UAAU;YACVD,QAAQ;QACV;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,SAAS2B,kBACdC,UAAqC,EACrC,EAACC,IAAI,EAAEC,KAAK,EAAkC,GAAG,CAAC,CAAC;IAEnD,OAAQF,WAAWrB,IAAI;QACrB,KAAK;YAAW;gBACd,OAAO;oBAACR,SAAS,CAAC,6BAA6B,EAAE6B,WAAW7B,OAAO,EAAE;oBAAEC,QAAQ;gBAAM;YACvF;QACA,KAAK;YAAS;gBACZ,MAAM,EAAC+B,WAAW,EAAC,GAAGH;gBACtB,MAAME,QAAQC,YAAYD,KAAK,IAAIC,YAAYC,OAAO;gBACtD,MAAMC,MAAMF,YAAYE,GAAG,IAAIvD,cAAcqD,YAAYG,cAAc,EAAEH,YAAYI,EAAE;gBACvF,OAAO;oBACLpC,SAAS,CAAC,iCAAiC,EAAE+B,MAAM,KAAK,EAAEG,KAAK;oBAC/DjC,QAAQ;oBACRoC,QAAQ;wBACNC,QAAQ;wBACRC,eAAeP,YAAYI,EAAE;wBAC7BL,OAAOC,YAAYD,KAAK,IAAI;wBAC5BG;oBACF;gBACF;YACF;QACA,KAAK;YAAW;gBACd,OAAO;oBACLlC,SAAShB;oBACTkB,UAAU;oBACVD,QAAQ;gBACV;YACF;QACA,KAAK;YAAe;gBAClB,OAAO;oBACLuC,UAAUhE,UAAUiE,WAAW;oBAC/BzC,SAAS,CAAC,oCAAoC,EAAE6B,WAAWa,QAAQ,CAACC,MAAM,CAAC,UAAU,EAAEd,WAAWa,QAAQ,CAACC,MAAM,KAAK,IAAI,gBAAgB,eAAe,gBAAgB,CAAC;oBAC1KzC,UAAU;oBACVD,QAAQ;gBACV;YACF;QACA,+EAA+E;QAC/E,KAAK;YAAgB;gBACnB,IAAI8B,OAAO;oBACT,OAAO;wBACL/B,SAAS,CAAC,gCAAgC,EAAE+B,MAAM,CAAC,EAAED,OAAO,CAAC,YAAY,EAAEA,KAAK,CAAC,CAAC,GAAG,IAAI;wBACzF7B,QAAQ;wBACRoC,QAAQ;4BACNC,QAAQ;4BACRC,eAAe;4BACf,GAAIT,OAAO;gCAACA;4BAAI,IAAI,CAAC,CAAC;4BACtBC;4BACAG,KAAK;wBACP;oBACF;gBACF;gBACA,OAAO;oBACLM,UAAUhE,UAAUiE,WAAW;oBAC/BzC,SAAS;oBACTE,UACE;oBACFD,QAAQ;gBACV;YACF;IACF;AACF;AAEA,OAAO,SAAS2C,uBAAuB3B,GAAY,EAAEkB,cAAkC;IACrF,OAAO,AAAClB,KAA+B4B,eAAe,MAClD,CAAC,oFAAoF,EAAEV,eAAe,4EAA4E,CAAC,GACnL,CAAC,iCAAiC,EAAEzD,gBAAgBuC,MAAM;AAChE;AAEA;;;;CAIC,GACD,OAAO,eAAe6B,eACpBnD,QAA6B,EAC7BoD,OAOK;IAEL,MAAM,EAAChB,KAAK,EAAC,GAAGgB;IAChB,IAAIA,QAAQ1B,cAAc,EAAE;QAC1B,MAAM,EAAC2B,KAAK,EAAElB,IAAI,EAAC,GAAGiB;QACtB,OAAOhE,QAAQY,UAAU;YACvBoB,OAAO1B;YACP6B,MAAM;YACNC,MAAM;gBACJ,MAAM8B,QAAQrB,kBAAkB,MAAMpC,oBAAoB;oBAACwD;gBAAK,IAAI;oBAAClB;oBAAMC;gBAAK;gBAChFpC,SAASI,MAAM,CAACkD;gBAChB,OAAOA,MAAMZ,MAAM,IAAI;YACzB;QACF;IACF;IAEA,MAAM,EAACW,KAAK,EAAEb,cAAc,EAAC,GAAGY;IAChC,OAAOhE,QAAQY,UAAU;QACvBoB,OAAO1B;QACP2B,aAAa,CAACC,MAAQ2B,uBAAuB3B,KAAKkB;QAClDjB,MAAM;QACNC,MAAM;YACJ,MAAM8B,QAAQrB,kBAAkB,MAAMtC,uBAAuB;gBAAC0D;gBAAOb;YAAc,IAAI;gBACrFJ;YACF;YACApC,SAASI,MAAM,CAACkD;YAChB,OAAOA,MAAMZ,MAAM,IAAI;QACzB;IACF;AACF;AAEA,yEAAyE,GACzE,OAAO,SAASa,qBACdrB,UAAwC,EACxC,EAACsB,UAAU,EAAEC,WAAW,EAAErB,KAAK,EAA+D;IAE9F,MAAMsB,YAAY,CAACC,OAAkBH,aAAaG,OAAO,CAAC,QAAQ,EAAEA,KAAK,cAAc,CAAC;IAExF,OAAQzB,WAAWrB,IAAI;QACrB,KAAK;YAAW;gBACd,OAAO;oBAACR,SAAS,CAAC,6BAA6B,EAAE6B,WAAW7B,OAAO,EAAE;oBAAEC,QAAQ;gBAAM;YACvF;QACA,KAAK;YAAS;gBACZ,MAAMiC,MAAML,WAAWG,WAAW,CAACE,GAAG,IAAImB,UAAUxB,WAAWG,WAAW,CAACC,OAAO;gBAClF,OAAO;oBACLjC,SAAS,CAAC,2BAA2B,EAAEkC,KAAK;oBAC5CjC,QAAQ;oBACRoC,QAAQ;wBACNC,QAAQ;wBACRC,eAAeV,WAAWG,WAAW,CAACI,EAAE;wBACxCL,OAAOF,WAAWG,WAAW,CAACD,KAAK,IAAI;wBACvCG;oBACF;gBACF;YACF;QACA,KAAK;YAAW;gBACd,OAAO;oBACL,4DAA4D;oBAC5DM,UAAUX,WAAW0B,MAAM,KAAK,iBAAiB/E,UAAUiE,WAAW,GAAG;oBACzEzC,SAAS6B,WAAW7B,OAAO;oBAC3BE,UAAU;oBACVD,QAAQ;gBACV;YACF;QACA,KAAK;YAAe;gBAClB,OAAO;oBACLuC,UAAUhE,UAAUiE,WAAW;oBAC/BzC,SAASmD,aAAa,sCAAsC;oBAC5DjD,UAAUiD,aACN,uEACA;oBACJlD,QAAQ;gBACV;YACF;QACA,KAAK;YAAgB;gBACnB,yFAAyF;gBACzF,MAAMiC,MAAMkB,cAAc,OAAOC,UAAUxB,WAAWI,OAAO;gBAC7D,MAAMuB,SAASzB,QAAQ,CAAC,SAAS,EAAEA,MAAM,CAAC,CAAC,GAAG;gBAC9C,OAAO;oBACL/B,SAASmD,aACL,CAAC,kCAAkC,EAAEtB,WAAWI,OAAO,GAAGuB,QAAQ,GAClE,CAAC,6BAA6B,EAAEtB,OAAOL,WAAWI,OAAO,GAAGuB,OAAO,yCAAyC,CAAC;oBACjHvD,QAAQ;oBACR,kEAAkE;oBAClE,6EAA6E;oBAC7EoC,QAAQ;wBAACC,QAAQ;wBAAUC,eAAe;wBAAMR,OAAOA,SAAS;wBAAMG;oBAAG;gBAC3E;YACF;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,eAAeuB,kBACpB9D,QAA6B,EAC7BoD,OAeK;IAEL,MAAM,EAAChB,KAAK,EAAC,GAAGgB;IAChB,MAAMW,UAAUX,QAAQ1B,cAAc,GAClC5B,uBAAuB;QAACuD,OAAOD,QAAQC,KAAK;QAAElB,MAAMiB,QAAQjB,IAAI;IAAA,KAChEvC,0BAA0BwD;IAC9B,4EAA4E;IAC5E,MAAMI,aAAaJ,QAAQ1B,cAAc,GAAG,QAAQ0B,QAAQI,UAAU;IAEtE,OAAOpE,QAAQY,UAAU;QACvBoB,OAAO1B;QACP2B,aAAa,CAACC,MAAQ,CAAC,iCAAiC,EAAEvC,gBAAgBuC,MAAM;QAChFC,MAAM;QACNC,MAAM;YACJ,MAAM8B,QAAQC,qBAAqB,MAAMQ,SAAS;gBAChDP;gBACAC,aAAa,CAAC,CAACL,QAAQ1B,cAAc;gBACrCU;YACF;YACApC,SAASI,MAAM,CAACkD;YAChB,OAAOA,MAAMZ,MAAM,IAAI;QACzB;IACF;AACF"}
@@ -4,7 +4,7 @@ import { createGzip } from 'node:zlib';
4
4
  import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
5
5
  import { exitCodes } from '@sanity/cli-core';
6
6
  import { spinner } from '@sanity/cli-core/ux';
7
- import { buildExposes, deployStudio as deployWorkbenchStudio, getApplicationUrl, getWorkbench } from '@sanity/workbench-cli/deploy';
7
+ import { buildExposes, createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench } from '@sanity/workbench-cli/deploy';
8
8
  import { pack } from 'tar-fs';
9
9
  import { createDeployment } from '../../services/userApplications.js';
10
10
  import { getAppId } from '../../util/appId.js';
@@ -79,7 +79,7 @@ export function deployStudio(options) {
79
79
  await checkStudioTarget(reporter, {
80
80
  appId,
81
81
  isWorkbenchApp: true,
82
- studioHost: cliConfig.studioHost,
82
+ slug: workbench.slug,
83
83
  title: appTitle
84
84
  });
85
85
  } else {
@@ -89,105 +89,143 @@ export function deployStudio(options) {
89
89
  reporter
90
90
  }));
91
91
  }
92
- await checkBuild(reporter, {
93
- build: ()=>buildStudio({
94
- autoUpdatesEnabled: isAutoUpdating,
95
- calledFromDeploy: true,
96
- cliConfig,
97
- flags,
98
- outDir: sourceDir,
99
- output,
100
- workDir
101
- }),
102
- skipReason: studioBuildSkipReason({
103
- build: flags.build,
104
- isExternal
105
- }),
106
- successMessage: 'Studio built'
107
- });
108
- if (!isExternal) {
109
- await verifyOutputDir({
110
- isWorkbenchApp,
111
- reporter,
112
- sourceDir
92
+ // A first deploy mints the app id and the build inlines it; --no-build would
93
+ // ship an existing bundle carrying a different id, so it can't be a first deploy.
94
+ if (workbench && !isExternal && !appId && !flags.build) {
95
+ reporter.report({
96
+ exitCode: exitCodes.USAGE_ERROR,
97
+ message: 'A first deploy cannot skip the build (--no-build)',
98
+ solution: 'Drop --no-build so the new application id is inlined into the build',
99
+ status: 'fail'
113
100
  });
114
101
  }
115
- // Report the exposes deploying with the studio, both modes. External studios
116
- // host their own bundle, so nothing registers.
117
- const exposes = workbench && !isExternal ? reportExposes(reporter, workbench) : [];
118
- // Dry run stops here everything below mutates.
119
- if (dryRun) return;
120
- // A real deploy has already exited if anything failed; landing here without a
121
- // resolved version means the deploy target was never resolved.
122
- if (!version) return;
123
- const studioManifest = await uploadStudioSchema(options, {
124
- isExternal
125
- });
126
- // Workbench studios deploy to Brett; plain studios use user-applications.
127
- if (workbench && !isExternal && organizationId) {
128
- const { applicationId } = await deployWorkbenchStudio({
129
- appId,
130
- icon: workbench.icon ? await readIconFromPath(workDir, workbench.icon) : undefined,
131
- interfaces: buildExposes(workbench, {
132
- appName: workbench.name,
133
- appTitle,
134
- exposesAppView: true,
135
- version
136
- }),
137
- isAutoUpdating,
102
+ // Read up front so a bad icon path fails before we create or build.
103
+ const appIcon = !dryRun && !isExternal && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
104
+ // Create the studio before the build so the bundle carries its real id. A
105
+ // redeploy already has it from `deployment.appId`; a dry run skips creation.
106
+ let applicationId = appId;
107
+ let applicationCreated = false;
108
+ let rollbackApp;
109
+ if (!dryRun && workbench && !isExternal && organizationId && !applicationId) {
110
+ ;
111
+ ({ applicationId, rollback: rollbackApp } = await createStudio({
138
112
  organizationId,
139
- output,
140
113
  projectId,
141
- sourceDir,
142
- studioHost: cliConfig.studioHost,
143
- title: appTitle,
144
- version,
145
- workspaces: toWorkspaces(studioManifest)
114
+ slug: workbench.slug,
115
+ title: appTitle
116
+ }));
117
+ applicationCreated = true;
118
+ }
119
+ // A record created above is stranded at its slug (and blocks retries) if any
120
+ // step before it fully deploys fails, so undo the creation on failure.
121
+ try {
122
+ await checkBuild(reporter, {
123
+ build: ()=>buildStudio({
124
+ applicationId: workbench ? applicationId : undefined,
125
+ autoUpdatesEnabled: isAutoUpdating,
126
+ calledFromDeploy: true,
127
+ cliConfig,
128
+ flags,
129
+ outDir: sourceDir,
130
+ output,
131
+ workDir
132
+ }),
133
+ skipReason: studioBuildSkipReason({
134
+ build: flags.build,
135
+ isExternal
136
+ }),
137
+ successMessage: 'Studio built'
146
138
  });
147
- const url = getApplicationUrl({
148
- id: applicationId,
149
- organizationId,
150
- type: 'studio'
139
+ if (!isExternal) {
140
+ await verifyOutputDir({
141
+ isWorkbenchApp,
142
+ reporter,
143
+ sourceDir
144
+ });
145
+ }
146
+ // Report the exposes deploying with the studio, both modes. External studios
147
+ // host their own bundle, so nothing registers.
148
+ const exposes = workbench && !isExternal ? reportExposes(reporter, workbench) : [];
149
+ // Dry run stops here — everything below mutates.
150
+ if (dryRun) return;
151
+ // A real deploy has already exited if anything failed; landing here without a
152
+ // resolved version means the deploy target was never resolved.
153
+ if (!version) return;
154
+ const studioManifest = await uploadStudioSchema(options, {
155
+ isExternal
151
156
  });
152
- logWorkbenchStudioDeployed({
153
- applicationId,
154
- cliConfig,
155
- output,
156
- url
157
+ // The studio was created (or resolved from `deployment.appId`) before the
158
+ // build, so this only ships the deployment; plain studios use user-applications.
159
+ if (workbench && !isExternal && organizationId && applicationId) {
160
+ await deployWorkbenchApp({
161
+ applicationId,
162
+ icon: appIcon,
163
+ interfaces: buildExposes(workbench, {
164
+ appName: workbench.name,
165
+ appTitle,
166
+ exposesAppView: true,
167
+ version
168
+ }),
169
+ isAutoUpdating,
170
+ label: 'Deploying to sanity.studio',
171
+ // Once the deployment is live, a metadata-sync failure must not delete
172
+ // the studio.
173
+ onDeployed: ()=>{
174
+ rollbackApp = undefined;
175
+ },
176
+ sourceDir,
177
+ title: appTitle,
178
+ version,
179
+ workspaces: toWorkspaces(studioManifest)
180
+ });
181
+ const url = getApplicationUrl({
182
+ id: applicationId,
183
+ organizationId,
184
+ type: 'studio'
185
+ });
186
+ logWorkbenchStudioDeployed({
187
+ applicationId,
188
+ cliConfig,
189
+ output,
190
+ url
191
+ });
192
+ return {
193
+ applicationType: 'studio',
194
+ applicationVersion: version,
195
+ ...exposes.length > 0 ? {
196
+ exposes
197
+ } : {},
198
+ target: {
199
+ action: applicationCreated ? 'create' : 'update',
200
+ applicationId,
201
+ title: appTitle,
202
+ url
203
+ }
204
+ };
205
+ }
206
+ if (!application) return;
207
+ const location = await shipStudioDeployment({
208
+ application,
209
+ isAutoUpdating,
210
+ isExternal,
211
+ options,
212
+ studioManifest,
213
+ version
157
214
  });
158
215
  return {
159
216
  applicationType: 'studio',
160
217
  applicationVersion: version,
161
- ...exposes.length > 0 ? {
162
- exposes
163
- } : {},
164
218
  target: {
165
- action: appId ? 'update' : 'create',
166
- applicationId,
167
- title: appTitle,
168
- url
219
+ action: studioCreated ? 'create' : 'update',
220
+ applicationId: application.id,
221
+ title: application.title ?? null,
222
+ url: location
169
223
  }
170
224
  };
225
+ } catch (err) {
226
+ await rollbackApp?.();
227
+ throw err;
171
228
  }
172
- if (!application) return;
173
- const location = await shipStudioDeployment({
174
- application,
175
- isAutoUpdating,
176
- isExternal,
177
- options,
178
- studioManifest,
179
- version
180
- });
181
- return {
182
- applicationType: 'studio',
183
- applicationVersion: version,
184
- target: {
185
- action: studioCreated ? 'create' : 'update',
186
- applicationId: application.id,
187
- title: application.title ?? null,
188
- url: location
189
- }
190
- };
191
229
  }
192
230
  /**
193
231
  * Finds the application a real deploy targets, registering a studio host when
@@ -333,6 +371,7 @@ function toWorkspaces(manifest) {
333
371
  icon: workspace.icon,
334
372
  name: workspace.name,
335
373
  projectId: workspace.projectId,
374
+ schemaDescriptorId: workspace.schemaDescriptorId,
336
375
  subtitle: workspace.subtitle,
337
376
  title: workspace.title
338
377
  }));