@sanity/cli 8.15.0 → 8.17.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/README.md CHANGED
@@ -140,6 +140,7 @@ Code for sanity cli
140
140
  - [`sanity users list`](#sanity-users-list)
141
141
  - [`sanity versions`](#sanity-versions)
142
142
  - [`sanity workflows abort INSTANCEID`](#sanity-workflows-abort-instanceid)
143
+ - [`sanity workflows blueprint generate`](#sanity-workflows-blueprint-generate)
143
144
  - [`sanity workflows definition delete NAME`](#sanity-workflows-definition-delete-name)
144
145
  - [`sanity workflows definition diff NAME`](#sanity-workflows-definition-diff-name)
145
146
  - [`sanity workflows definition list`](#sanity-workflows-definition-list)
@@ -2027,7 +2028,7 @@ FLAGS
2027
2028
  --source-maps Enable source maps for built bundles (increases size of bundle)
2028
2029
  --title=<value> Title for a newly created application or studio. For apps, use --create to select creation
2029
2030
  when the organization already has apps
2030
- --url=<value> Studio URL for deployment. For external studios, the full URL. For hosted studios, the
2031
+ --url=<value> Studio URL for deployment. For external deploys, the full URL. For hosted studios, the
2031
2032
  hostname (e.g. "my-studio" or "my-studio.sanity.studio")
2032
2033
  --verbose Enable verbose logging
2033
2034
 
@@ -2051,6 +2052,10 @@ EXAMPLES
2051
2052
 
2052
2053
  $ sanity deploy --external
2053
2054
 
2055
+ Register an externally hosted studio, served from the provided origin
2056
+
2057
+ $ sanity deploy --external --url https://apps.example.com
2058
+
2054
2059
  Create and deploy an App SDK app without prompts. Save application.id as deployment.appId, then omit --create on
2055
2060
  later deploys
2056
2061
 
@@ -4269,6 +4274,8 @@ DESCRIPTION
4269
4274
  Note:
4270
4275
  - The `sanity schema extract` command is a prerequisite for extracting your Sanity Studio schema into a `schema.json`
4271
4276
  file, which is then used by the `sanity typegen generate` command to generate type definitions.
4277
+ - To generate types for several datasets, list them in `typegen.resources` in `sanity.cli.ts` (beta). Each resource
4278
+ uses its own `schema` file, or the schema bound to its dataset when `schema` is omitted.
4272
4279
 
4273
4280
  EXAMPLES
4274
4281
  Generate TypeScript type definitions from a Sanity Studio schema extracted using the `sanity schema extract`
@@ -4435,6 +4442,30 @@ EXAMPLES
4435
4442
  $ sanity workflows abort wf-instance.abc123 --reason 'superseded by relaunch'
4436
4443
  ```
4437
4444
 
4445
+ ## `sanity workflows blueprint generate`
4446
+
4447
+ Experimental: generate the Sanity Blueprints runtime the definitions require, next to sanity.workflow.ts. Writes the workflow resources, one function per derived need, the effect-handler registry, and a handler stub per declared effect. Covers every deployment in the config, because the emitted resources module declares them all. These flags and this output may change before the Blueprints backend accepts the sanity.workflow resource.
4448
+
4449
+ ```
4450
+ USAGE
4451
+ $ sanity workflows blueprint generate [--check]
4452
+
4453
+ FLAGS
4454
+ --check Experimental: verify the tree on disk still matches the definitions; write nothing and exit non-zero on any
4455
+ difference. The CI drift gate.
4456
+
4457
+ DESCRIPTION
4458
+ Experimental: generate the Sanity Blueprints runtime the definitions require, next to sanity.workflow.ts. Writes the
4459
+ workflow resources, one function per derived need, the effect-handler registry, and a handler stub per declared
4460
+ effect. Covers every deployment in the config, because the emitted resources module declares them all. These flags and
4461
+ this output may change before the Blueprints backend accepts the sanity.workflow resource.
4462
+
4463
+ EXAMPLES
4464
+ $ sanity workflows blueprint generate
4465
+
4466
+ $ sanity workflows blueprint generate --check
4467
+ ```
4468
+
4438
4469
  ## `sanity workflows definition delete NAME`
4439
4470
 
4440
4471
  Delete a deployed workflow definition (every version, or one via --version). Refuses while non-terminal instances exist unless --cascade aborts them first — instances are aborted in place, never deleted.
@@ -4542,7 +4573,7 @@ DESCRIPTION
4542
4573
 
4543
4574
  ## `sanity workflows deploy`
4544
4575
 
4545
- Validate, diff, and deploy workflow definitions to the resource bound by the selected deployment.
4576
+ Validate workflow definitions, check any generated runtime beside the config against them, then diff and deploy to the resource bound by the selected deployment. A generated runtime that no longer matches the definitions fails the deploy before anything is written; regenerate it with `sanity-workflows blueprint generate`.
4546
4577
 
4547
4578
  ```
4548
4579
  USAGE
@@ -4551,11 +4582,13 @@ USAGE
4551
4582
 
4552
4583
  FLAGS
4553
4584
  --all-tags Deploy every deployment in the config, not just a selection.
4554
- --check Validate definitions only; do not contact the dataset.
4585
+ --check Validate definitions and check any generated runtime against them; do not contact the dataset.
4555
4586
  --deployment=<value> Deployment name — the unique identity of one deployment in the config.
4556
- --dry-run Validate + diff against the deployed version; do not write.
4587
+ --dry-run Validate definitions, check any generated runtime against them, and diff against the deployed
4588
+ version; do not write.
4557
4589
  --only=<value> Limit deploy/check/diff to a single workflow definition by name (deployments are selected with
4558
- --deployment). Every targeted deployment must contain it.
4590
+ --deployment). Every targeted deployment must contain it. The generated-runtime check still
4591
+ covers the whole config, because the generated tree declares every deployment in it.
4559
4592
  --[no-]share-defs Share the definition documents newly created by this deploy with Sanity — the full document,
4560
4593
  verbatim (structure, names, filters, effect configuration, seeded values), plus its deployment
4561
4594
  coordinates (project and dataset, or resource id); never content documents, instances, or your
@@ -4565,7 +4598,9 @@ FLAGS
4565
4598
  an environment group).
4566
4599
 
4567
4600
  DESCRIPTION
4568
- Validate, diff, and deploy workflow definitions to the resource bound by the selected deployment.
4601
+ Validate workflow definitions, check any generated runtime beside the config against them, then diff and deploy to the
4602
+ resource bound by the selected deployment. A generated runtime that no longer matches the definitions fails the deploy
4603
+ before anything is written; regenerate it with `sanity-workflows blueprint generate`.
4569
4604
 
4570
4605
  EXAMPLES
4571
4606
  $ sanity workflows deploy --deployment review-prod
@@ -10,6 +10,7 @@ import { getAutoUpdateIssueMessage, getAutoUpdateMigrationHint, resolveAutoUpdat
10
10
  import { checkDir } from './checkDir.js';
11
11
  import { deployDebug } from './deployDebug.js';
12
12
  import { resolveAppDeployTarget, resolveStudioDeployTarget, resolveWorkbenchApp, resolveWorkbenchStudio } from './resolveDeployTarget.js';
13
+ import { normalizeUrl, validateUrl } from './urlUtils.js';
13
14
  export async function checkPackageVersion(reporter, { moduleName, workDir }) {
14
15
  const version = await getLocalPackageVersion(moduleName, workDir);
15
16
  reporter.report(version ? {
@@ -64,6 +65,48 @@ export function checkAutoUpdates(reporter, { cliConfig, flags }) {
64
65
  });
65
66
  }
66
67
  }
68
+ /**
69
+ * The origin a federated studio deployed with --external is registered
70
+ * at. Only a first deploy registers one; a redeploy keeps the URL it has.
71
+ */ export function checkExternalUrl(reporter, { appId, url }) {
72
+ if (appId) return undefined;
73
+ if (!url) {
74
+ reporter.report({
75
+ exitCode: exitCodes.USAGE_ERROR,
76
+ message: 'A first external deploy needs the URL your host serves the build from',
77
+ solution: 'Pass it with --url, for example --url https://studio.example.com',
78
+ status: 'fail'
79
+ });
80
+ return undefined;
81
+ }
82
+ const normalized = normalizeUrl(url);
83
+ const validation = validateUrl(normalized);
84
+ if (validation !== true) {
85
+ reporter.report({
86
+ exitCode: exitCodes.USAGE_ERROR,
87
+ message: validation,
88
+ solution: 'Pass --url with an http or https URL, for example --url https://studio.example.com',
89
+ status: 'fail'
90
+ });
91
+ return undefined;
92
+ }
93
+ // The Dashboard loads the remote from the origin root, so a path would never be fetched.
94
+ const { hash, origin, pathname, search } = new URL(normalized);
95
+ if (pathname !== '/' || search || hash) {
96
+ reporter.report({
97
+ exitCode: exitCodes.USAGE_ERROR,
98
+ message: '--url must be an origin with no path, query or hash',
99
+ solution: 'Pass the origin your host serves the build from, for example --url https://studio.example.com',
100
+ status: 'fail'
101
+ });
102
+ return undefined;
103
+ }
104
+ reporter.report({
105
+ message: `Registers at ${origin}`,
106
+ status: 'pass'
107
+ });
108
+ return origin;
109
+ }
67
110
  export async function checkBuild(reporter, { build, skipReason, successMessage }) {
68
111
  if (skipReason) {
69
112
  reporter.report({
@@ -343,7 +386,7 @@ export function describeAppTargetError(err, organizationId) {
343
386
  */ export async function checkStudioTarget(reporter, options) {
344
387
  const { title } = options;
345
388
  const resolve = options.isWorkbenchApp ? resolveWorkbenchStudio(options) : resolveStudioDeployTarget(options);
346
- // Workbench studios always deploy to Sanity hosting, never an external URL.
389
+ // A workbench studio's target is its slug, even when its build is hosted externally.
347
390
  const isExternal = options.isWorkbenchApp ? false : options.isExternal;
348
391
  return runStep(reporter, {
349
392
  debug: deployDebug,
@@ -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} 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 type DeployTargetApp,\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 /** `null` until the deploy creates the application. */\n id: string | null\n title: string | null\n type: 'coreApp' | 'studio'\n url: string | null\n\n /** Absent on a plain app, whose backend reports `appHost` instead. */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** The backend's record, verbatim; `--json` reports it once the deploy succeeds. */\n application?: object\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\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'}\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 {title}: {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 application,\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: application.id,\n title: application.title,\n type: 'coreApp',\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:\n 'Set `deployment.appId` in sanity.cli.ts to deploy to an existing app, or run `sanity deploy --create --title \"<name>\" --yes` to create a new one',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n const {appHost} = resolution\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${appHost ? ` with slug \"${appHost}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n id: null,\n ...(appHost ? {slug: appHost} : {}),\n title,\n type: 'coreApp',\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\n/** One diagnosis for both the app and studio verdicts: they share a slug namespace. */\nfunction describeSlugTaken({\n appHost,\n existing,\n}: {\n appHost: string\n existing: DeployTargetApp\n}): DeployCheck {\n return {\n application: existing,\n exitCode: exitCodes.USAGE_ERROR,\n message: `An application already exists at slug \"${appHost}\" in this organization (app ID ${existing.id})`,\n solution: `Add \\`deployment: {appId: '${existing.id}'}\\` to sanity.cli.ts to redeploy it`,\n status: 'fail',\n target: {\n action: 'update',\n id: existing.id,\n title: existing.title,\n type: existing.type,\n url: existing.url ?? null,\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 | {\n appId: string | undefined\n create?: boolean\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n organizationId?: string\n slug?: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, organizationId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const resolution = await resolveWorkbenchApp({appId, organizationId, slug})\n const check = describeAppTarget(resolution, {title})\n reporter.report(check)\n return check\n },\n })\n }\n\n const {appId, create, 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(\n await resolveAppDeployTarget({appId, create, organizationId}),\n {\n title,\n },\n )\n reporter.report(check)\n return check\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 {appHost} = resolution.application\n const url = resolution.application.url ?? (appHost ? studioUrl(appHost) : null)\n return {\n application: resolution.application,\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: resolution.application.id,\n title: resolution.application.title,\n type: 'studio',\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 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n case 'would-create': {\n const appHost = resolution.appHost\n const url = isWorkbench ? null : studioUrl(appHost)\n const result = {\n status: 'pass',\n target: {action: 'create', id: null, title: title || null, type: 'studio', url},\n } as const\n const titled = title ? ` titled \"${title}\"` : ''\n\n if (isExternal) {\n return {\n message: `Would register external studio at ${appHost}${titled}`,\n ...result,\n }\n }\n\n if (isWorkbench) {\n return {\n message: `Would create a new studio${title ? ` \"${title}\"` : ''} with slug \"${appHost}\" (name availability is checked on deploy)`,\n ...result,\n target: {...result.target, slug: appHost},\n }\n }\n\n return {\n message: `Would create studio hostname ${url}${titled} (name availability is checked on deploy)`,\n ...result,\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 organizationId?: string\n slug: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio(options)\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\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","title","application","appHost","url","organizationId","id","target","action","exitCode","USAGE_ERROR","existing","length","describeSlugTaken","slug","describeAppTargetError","statusCode","checkAppTarget","options","appId","check","create","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","result","titled","checkStudioTarget","resolve"],"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} 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 type DeployTargetApp,\n resolveAppDeployTarget,\n resolveStudioDeployTarget,\n resolveWorkbenchApp,\n resolveWorkbenchStudio,\n type StudioDeployTargetResolution,\n} from './resolveDeployTarget.js'\nimport {type DeployFlags} from './types.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.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 /** `null` until the deploy creates the application. */\n id: string | null\n title: string | null\n type: 'coreApp' | 'studio'\n url: string | null\n\n /** Absent on a plain app, whose backend reports `appHost` instead. */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** The backend's record, verbatim; `--json` reports it once the deploy succeeds. */\n application?: object\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\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'}\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\n/**\n * The origin a federated studio deployed with --external is registered\n * at. Only a first deploy registers one; a redeploy keeps the URL it has.\n */\nexport function checkExternalUrl(\n reporter: DeployCheckReporter,\n {appId, url}: {appId: string | undefined; url: string | undefined},\n): string | undefined {\n if (appId) return undefined\n\n if (!url) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first external deploy needs the URL your host serves the build from',\n solution: 'Pass it with --url, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n const normalized = normalizeUrl(url)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: validation,\n solution:\n 'Pass --url with an http or https URL, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n // The Dashboard loads the remote from the origin root, so a path would never be fetched.\n const {hash, origin, pathname, search} = new URL(normalized)\n if (pathname !== '/' || search || hash) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: '--url must be an origin with no path, query or hash',\n solution:\n 'Pass the origin your host serves the build from, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n reporter.report({message: `Registers at ${origin}`, status: 'pass'})\n return origin\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 {title}: {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 application,\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: application.id,\n title: application.title,\n type: 'coreApp',\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:\n 'Set `deployment.appId` in sanity.cli.ts to deploy to an existing app, or run `sanity deploy --create --title \"<name>\" --yes` to create a new one',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n const {appHost} = resolution\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${appHost ? ` with slug \"${appHost}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n id: null,\n ...(appHost ? {slug: appHost} : {}),\n title,\n type: 'coreApp',\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\n/** One diagnosis for both the app and studio verdicts: they share a slug namespace. */\nfunction describeSlugTaken({\n appHost,\n existing,\n}: {\n appHost: string\n existing: DeployTargetApp\n}): DeployCheck {\n return {\n application: existing,\n exitCode: exitCodes.USAGE_ERROR,\n message: `An application already exists at slug \"${appHost}\" in this organization (app ID ${existing.id})`,\n solution: `Add \\`deployment: {appId: '${existing.id}'}\\` to sanity.cli.ts to redeploy it`,\n status: 'fail',\n target: {\n action: 'update',\n id: existing.id,\n title: existing.title,\n type: existing.type,\n url: existing.url ?? null,\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 | {\n appId: string | undefined\n create?: boolean\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n organizationId?: string\n slug?: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, organizationId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const resolution = await resolveWorkbenchApp({appId, organizationId, slug})\n const check = describeAppTarget(resolution, {title})\n reporter.report(check)\n return check\n },\n })\n }\n\n const {appId, create, 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(\n await resolveAppDeployTarget({appId, create, organizationId}),\n {\n title,\n },\n )\n reporter.report(check)\n return check\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 {appHost} = resolution.application\n const url = resolution.application.url ?? (appHost ? studioUrl(appHost) : null)\n return {\n application: resolution.application,\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: resolution.application.id,\n title: resolution.application.title,\n type: 'studio',\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 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n case 'would-create': {\n const appHost = resolution.appHost\n const url = isWorkbench ? null : studioUrl(appHost)\n const result = {\n status: 'pass',\n target: {action: 'create', id: null, title: title || null, type: 'studio', url},\n } as const\n const titled = title ? ` titled \"${title}\"` : ''\n\n if (isExternal) {\n return {\n message: `Would register external studio at ${appHost}${titled}`,\n ...result,\n }\n }\n\n if (isWorkbench) {\n return {\n message: `Would create a new studio${title ? ` \"${title}\"` : ''} with slug \"${appHost}\" (name availability is checked on deploy)`,\n ...result,\n target: {...result.target, slug: appHost},\n }\n }\n\n return {\n message: `Would create studio hostname ${url}${titled} (name availability is checked on deploy)`,\n ...result,\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 organizationId?: string\n slug: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio(options)\n : resolveStudioDeployTarget(options)\n // A workbench studio's target is its slug, even when its build is hosted externally.\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\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","normalizeUrl","validateUrl","checkPackageVersion","reporter","moduleName","workDir","version","report","message","status","solution","checkAutoUpdates","cliConfig","flags","enabled","issue","type","autoUpdates","checkAppId","checkExternalUrl","appId","url","undefined","exitCode","USAGE_ERROR","normalized","validation","hash","origin","pathname","search","URL","checkBuild","build","skipReason","successMessage","debug","formatError","err","name","work","verifyOutputDir","isWorkbenchApp","sourceDir","spin","start","verifyBuild","succeed","fail","describeAppTarget","resolution","title","application","appHost","organizationId","id","target","action","existing","length","describeSlugTaken","slug","describeAppTargetError","statusCode","checkAppTarget","options","check","create","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","result","titled","checkStudioTarget","resolve"],"mappings":"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"}
@@ -1,18 +1,18 @@
1
- import { basename, dirname } from 'node:path';
1
+ import { basename, dirname, relative } from 'node:path';
2
2
  import { styleText } from 'node:util';
3
3
  import { createGzip } from 'node:zlib';
4
4
  import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
5
5
  import { readIconFromPath } from '@sanity/cli-build/_internal/manifest';
6
6
  import { exitCodes } from '@sanity/cli-core';
7
7
  import { spinner } from '@sanity/cli-core/ux';
8
- import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
8
+ import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
9
9
  import { c as createTar } from 'tar';
10
10
  import { createDeployment } from '../../services/userApplications.js';
11
11
  import { getAppId } from '../../util/appId.js';
12
12
  import { NO_ORGANIZATION_ID, NO_PROJECT_ID } from '../../util/errorMessages.js';
13
13
  import { buildStudio } from '../build/buildStudio.js';
14
14
  import { createStudioUserApplication } from './createUserApplication.js';
15
- import { checkAutoUpdates, checkBuild, checkPackageVersion, checkStudioTarget, verifyOutputDir } from './deployChecks.js';
15
+ import { checkAutoUpdates, checkBuild, checkExternalUrl, checkPackageVersion, checkStudioTarget, verifyOutputDir } from './deployChecks.js';
16
16
  import { deployDebug } from './deployDebug.js';
17
17
  import { listDeploymentFiles, reportInterfaces } from './deploymentPlan.js';
18
18
  import { runDeploy } from './deployRunner.js';
@@ -36,16 +36,9 @@ export function deployStudio(options) {
36
36
  const organizationId = cliConfig.app?.organizationId;
37
37
  const appId = getAppId(cliConfig);
38
38
  const dryRun = !!flags['dry-run'];
39
- // A federated app deploys through Sanity's build/hosting pipeline, which
40
- // --external skips — fail before doing any other work.
41
- if (isExternal && isWorkbenchApp) {
42
- reporter.report({
43
- exitCode: exitCodes.USAGE_ERROR,
44
- message: 'Deploying a federated application to an external host is not yet supported',
45
- solution: 'Remove the --external flag to deploy to Sanity hosting',
46
- status: 'fail'
47
- });
48
- }
39
+ // A legacy external studio only registers its URL; a federated one is built
40
+ // and deployed like a hosted one, minus the upload.
41
+ const isLegacyExternal = isExternal && !isWorkbenchApp;
49
42
  const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug : '';
50
43
  const isAutoUpdating = checkAutoUpdates(reporter, {
51
44
  cliConfig,
@@ -68,7 +61,8 @@ export function deployStudio(options) {
68
61
  let application = null;
69
62
  let studioCreated = false;
70
63
  let workbenchApp;
71
- if (workbench && !isExternal) {
64
+ let externalUrl;
65
+ if (workbench) {
72
66
  reporter.report(organizationId ? {
73
67
  message: `Organization: ${organizationId}`,
74
68
  status: 'pass'
@@ -84,6 +78,10 @@ export function deployStudio(options) {
84
78
  slug: workbench.slug,
85
79
  title: appTitle
86
80
  }))?.application;
81
+ if (isExternal) externalUrl = checkExternalUrl(reporter, {
82
+ appId,
83
+ url: flags.url
84
+ });
87
85
  } else {
88
86
  ;
89
87
  ({ application, created: studioCreated } = await resolveStudioApplication(options, {
@@ -91,9 +89,11 @@ export function deployStudio(options) {
91
89
  reporter
92
90
  }));
93
91
  }
92
+ // A redeploy follows how the application was registered, so --external is only needed once.
93
+ const isExternallyHosted = isExternal || !!workbenchApp?.externalUrl;
94
94
  // A first deploy mints the app id and the build inlines it; --no-build would
95
95
  // ship an existing bundle carrying a different id, so it can't be a first deploy.
96
- if (workbench && !isExternal && !appId && !flags.build) {
96
+ if (workbench && !appId && !flags.build) {
97
97
  reporter.report({
98
98
  exitCode: exitCodes.USAGE_ERROR,
99
99
  message: 'A first deploy cannot skip the build (--no-build)',
@@ -102,14 +102,15 @@ export function deployStudio(options) {
102
102
  });
103
103
  }
104
104
  // Read up front so a bad icon path fails before we create or build.
105
- const appIcon = !dryRun && !isExternal && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
105
+ const appIcon = !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
106
106
  // Create the studio before the build so the bundle carries its real id. A
107
107
  // redeploy already has it from `deployment.appId`; a dry run skips creation.
108
108
  let applicationId = appId;
109
109
  let applicationCreated = false;
110
110
  let rollbackApp;
111
- if (!dryRun && workbench && !isExternal && organizationId && !applicationId) {
111
+ if (!dryRun && workbench && organizationId && !applicationId) {
112
112
  const created = await createStudio({
113
+ externalUrl,
113
114
  name: workbench.name,
114
115
  organizationId,
115
116
  projectId,
@@ -138,19 +139,18 @@ export function deployStudio(options) {
138
139
  }),
139
140
  skipReason: studioBuildSkipReason({
140
141
  build: flags.build,
141
- isExternal
142
+ isLegacyExternal
142
143
  }),
143
144
  successMessage: 'Studio built'
144
145
  });
145
- if (!isExternal) {
146
+ if (!isLegacyExternal) {
146
147
  await verifyOutputDir({
147
148
  isWorkbenchApp,
148
149
  reporter,
149
150
  sourceDir
150
151
  });
151
152
  }
152
- // An external studio hosts its own bundle, so nothing registers.
153
- const interfaces = workbench && !isExternal ? reportInterfaces(reporter, workbench) : null;
153
+ const interfaces = workbench ? reportInterfaces(reporter, workbench) : null;
154
154
  const payload = {
155
155
  appId: appId ?? null,
156
156
  isAutoUpdating,
@@ -177,11 +177,11 @@ export function deployStudio(options) {
177
177
  if (!version) return;
178
178
  const studioManifest = await uploadStudioSchema(options, {
179
179
  applicationId: workbench ? applicationId : undefined,
180
- isExternal
180
+ isExternal: isLegacyExternal
181
181
  });
182
182
  // The studio was created (or resolved from `deployment.appId`) before the
183
183
  // build, so this only ships the deployment; plain studios use user-applications.
184
- if (workbench && !isExternal && organizationId && applicationId) {
184
+ if (workbench && organizationId && applicationId) {
185
185
  await deployWorkbenchApp({
186
186
  access: toAccess(studioManifest),
187
187
  app: cliConfig.app,
@@ -189,6 +189,7 @@ export function deployStudio(options) {
189
189
  icon: appIcon,
190
190
  isApp: false,
191
191
  isAutoUpdating,
192
+ isExternal: isExternallyHosted,
192
193
  label: 'Deploying studio',
193
194
  // Once the deployment is live, a metadata-sync failure must not delete
194
195
  // the studio.
@@ -213,6 +214,12 @@ export function deployStudio(options) {
213
214
  output,
214
215
  url
215
216
  });
217
+ if (isExternallyHosted) logExternalHost({
218
+ built: flags.build,
219
+ organizationId,
220
+ output,
221
+ sourceDir
222
+ });
216
223
  return {
217
224
  action: applicationCreated ? 'create' : 'update',
218
225
  application: workbenchApp ?? null,
@@ -409,8 +416,16 @@ function toWorkspaces(manifest) {
409
416
  output.log(`to the \`deployment\` section in sanity.cli.js or sanity.cli.ts`);
410
417
  output.log(`to avoid prompting for application id on next deploy.`);
411
418
  }
412
- function studioBuildSkipReason({ build, isExternal }) {
413
- if (isExternal) return 'Build skipped for externally hosted studios';
419
+ /** Tells the customer what their host must do for the Dashboard to load the studio from it. */ function logExternalHost({ built, organizationId, output, sourceDir }) {
420
+ const dir = `${relative(process.cwd(), sourceDir) || '.'}/`;
421
+ output.log(`
422
+ The Dashboard loads this studio from your host, which must:
423
+ 1. Serve ${dir} unchanged at the root of its URL (/mf-manifest.json, /remoteEntry-*.js, /static/*)
424
+ 2. Send Access-Control-Allow-Origin for ${getWorkbenchUrl(organizationId)}
425
+ 3. Respond without cookies or a sign-in${built ? `\n\nThis deploy rebuilt ${dir}: copy it to your host before opening the studio in the Dashboard.` : ''}`);
426
+ }
427
+ function studioBuildSkipReason({ build, isLegacyExternal }) {
428
+ if (isLegacyExternal) return 'Build skipped for externally hosted studios';
414
429
  if (!build) return 'Build skipped (--no-build) — validating existing output directory';
415
430
  return;
416
431
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployStudio.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip, type Gzip} from 'node:zlib'\n\nimport {formatSchemaValidation, SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {readIconFromPath} from '@sanity/cli-build/_internal/manifest'\nimport {exitCodes} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n type BrettAccess,\n type BrettWorkspace,\n createStudio,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {type StudioManifest} from 'sanity'\nimport {c as createTar} from 'tar'\n\nimport {createDeployment, type UserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {NO_ORGANIZATION_ID, NO_PROJECT_ID} from '../../util/errorMessages.js'\nimport {buildStudio} from '../build/buildStudio.js'\nimport {createStudioUserApplication} from './createUserApplication.js'\nimport {\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n checkStudioTarget,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {deployStudioSchemasAndManifests} from './deployStudioSchemasAndManifests.js'\nimport {findUserApplicationForStudio} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst STUDIO_PACKAGE = 'sanity'\n\nexport function deployStudio(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({flags, projectRoot, sourceDir}) =>\n flags.external ? Promise.resolve([]) : listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runStudioDeployment,\n type: 'studio',\n })\n}\n\n/** Validates the deploy, extracts and uploads the schema, and ships the build. */\nasync function runStudioDeployment(\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 isExternal = !!flags.external\n const workbench = getWorkbench(cliConfig)\n const isWorkbenchApp = workbench !== null\n const projectId = cliConfig.api?.projectId\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A federated app deploys through Sanity's build/hosting pipeline, which\n // --external skips — fail before doing any other work.\n if (isExternal && isWorkbenchApp) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Deploying a federated application to an external host is not yet supported',\n solution: 'Remove the --external flag to deploy to Sanity hosting',\n status: 'fail',\n })\n }\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n const version = await checkPackageVersion(reporter, {\n moduleName: STUDIO_PACKAGE,\n workDir,\n })\n\n reporter.report(\n projectId\n ? {message: `Project: ${projectId}`, status: 'pass'}\n : {\n message: NO_PROJECT_ID,\n solution: 'Add `api.projectId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n // Workbench studios deploy to Brett (which needs the org); plain studios\n // resolve/create on user-applications, unchanged.\n let application: UserApplication | null = null\n let studioCreated = false\n let workbenchApp: object | undefined\n if (workbench && !isExternal) {\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 workbenchApp = (\n await checkStudioTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else {\n ;({application, created: studioCreated} = await resolveStudioApplication(options, {\n dryRun,\n reporter,\n }))\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 (workbench && !isExternal && !appId && !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 && !isExternal && workbench?.icon\n ? await readIconFromPath(workDir, workbench.icon)\n : undefined\n\n // Create the studio 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 && workbench && !isExternal && organizationId && !applicationId) {\n const created = await createStudio({\n name: workbench.name,\n organizationId,\n projectId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\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 buildStudio({\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: studioBuildSkipReason({build: flags.build, isExternal}),\n successMessage: 'Studio built',\n })\n\n if (!isExternal) {\n await verifyOutputDir({isWorkbenchApp, reporter, sourceDir})\n }\n\n // An external studio hosts its own bundle, so nothing registers.\n const interfaces = workbench && !isExternal ? reportInterfaces(reporter, workbench) : null\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n ...(projectId ? {projectId} : {}),\n type: 'studio',\n version,\n ...toWorkbenchPayload(workbench, {interfaces, title: appTitle}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved version means the deploy target was never resolved.\n if (!version) return\n\n const studioManifest = await uploadStudioSchema(options, {\n applicationId: workbench ? applicationId : undefined,\n isExternal,\n })\n // The studio was created (or resolved from `deployment.appId`) before the\n // build, so this only ships the deployment; plain studios use user-applications.\n if (workbench && !isExternal && organizationId && applicationId) {\n await deployWorkbenchApp({\n access: toAccess(studioManifest),\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: false,\n isAutoUpdating,\n label: 'Deploying studio',\n // Once the deployment is live, a metadata-sync failure must not delete\n // the studio.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n workspaces: toWorkspaces(studioManifest),\n })\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'studio'})\n logWorkbenchStudioDeployed({applicationId, cliConfig, output, url})\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n if (!application) return\n const location = await shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n })\n\n return {\n action: studioCreated ? 'create' : 'update',\n application,\n payload,\n url: location,\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, registering a studio host when\n * none is configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveStudioApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplication | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const isExternal = !!flags.external\n const appId = getAppId(cliConfig)\n // Sets the title on a newly registered studio; blank falls back to undefined\n const title = flags.title?.trim() || undefined\n\n if (dryRun) {\n await checkStudioTarget(reporter, {\n appId,\n isExternal,\n projectId: cliConfig.api?.projectId,\n studioHost: cliConfig.studioHost,\n title,\n urlFlag: flags.url,\n })\n return {application: null, created: false}\n }\n\n const projectId = cliConfig.api?.projectId ?? ''\n // `created` is true when a configured-but-unregistered host was just registered.\n const {application, created} = await findUserApplicationForStudio({\n appId,\n isExternal,\n output,\n projectId,\n studioHost: cliConfig.studioHost,\n title,\n unattended: !!flags.yes,\n urlFlag: flags.url,\n })\n\n if (!application) {\n if (isExternal) {\n output.log('Your project has not been registered with an external studio URL.')\n output.log('Please enter the full URL where your studio is hosted.')\n } else {\n output.log('Your project has not been assigned a studio hostname.')\n output.log('To deploy your Sanity Studio to our hosted sanity.studio service,')\n output.log('you will need one. Please enter the subdomain you want to use.')\n }\n\n const registered = await createStudioUserApplication({\n projectId,\n title,\n urlType: isExternal ? 'external' : 'internal',\n })\n deployDebug('Created user application', registered)\n return {application: registered, created: true}\n }\n\n deployDebug('Found user application', application)\n return {application, created}\n}\n\n/** Extracts the studio schema and manifest and uploads them to the schema store. */\nasync function uploadStudioSchema(\n options: DeployAppOptions,\n {applicationId, isExternal}: {applicationId?: string; isExternal: boolean},\n): Promise<StudioManifest | null> {\n const {cliConfig, flags, output, projectRoot, sourceDir} = options\n\n let studioManifest: StudioManifest | null = null\n try {\n studioManifest = await deployStudioSchemasAndManifests(\n {\n applicationId,\n configPath: projectRoot.path,\n isExternal,\n outPath: `${sourceDir}/static`,\n projectId: cliConfig.api?.projectId ?? '',\n schemaRequired: flags['schema-required'],\n verbose: flags.verbose,\n workDir: projectRoot.directory,\n },\n output,\n )\n } catch (error) {\n deployDebug('Error deploying studio schemas and manifests', error)\n if (error instanceof SchemaExtractionError && error.validation?.length) {\n output.error(formatSchemaValidation(error.validation), {exit: exitCodes.RUNTIME_ERROR})\n }\n output.error(`Error deploying studio schemas and manifests: ${error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!studioManifest) {\n output.error('Failed to generate studio manifest. Please check your schemas and manifests.', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n return studioManifest\n}\n\nasync function shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n isExternal: boolean\n options: DeployAppOptions\n studioManifest: StudioManifest | null\n version: string\n}): Promise<string> {\n const {cliConfig, output, sourceDir} = options\n\n let tarball: Gzip | undefined\n if (!isExternal) {\n tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n }\n\n const spin = spinner(isExternal ? 'Registering studio' : 'Deploying to sanity.studio').start()\n let location: string\n try {\n ;({location} = await createDeployment({\n applicationId: application.id,\n isApp: false,\n isAutoUpdating,\n manifest: studioManifest,\n projectId: cliConfig.api?.projectId,\n tarball,\n version,\n }))\n } catch (error) {\n spin.fail()\n throw error\n }\n spin.succeed()\n\n const named = application.title ? ` — \"${application.title}\"` : ''\n output.log(\n isExternal\n ? `\\nSuccess! Studio registered${named}`\n : `\\nSuccess! Studio deployed to ${styleText('cyan', location)}${named}`,\n )\n\n if (getAppId(cliConfig)) return location\n\n const example = `Example:\nexport default defineCliConfig({\n //…\n deployment: {\n ${styleText('cyan', `appId: '${application.id}'`)},\n },\n //…\n})`\n output.log(`\\nAdd ${styleText('cyan', `appId: '${application.id}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n output.log(`\\n${example}`)\n\n return location\n}\n\n/**\n * One `datasets` access entry per unique workspace dataset, with a `resourceId`\n * of `\"<projectId>.<dataset>\"`. Deduped, since workspaces can share a dataset.\n */\nfunction toAccess(manifest: StudioManifest | null): BrettAccess[] {\n const resourceIds = new Set(\n (manifest?.workspaces ?? []).map((w) => `${w.projectId}.${w.dataset}`),\n )\n return [...resourceIds].map(\n (resourceId) => ({resourceId, resourceType: 'dataset'}) satisfies BrettAccess,\n )\n}\n\nfunction toWorkspaces(manifest: StudioManifest | null): BrettWorkspace[] {\n return (manifest?.workspaces ?? []).map((workspace) => ({\n basePath: workspace.basePath,\n dataset: workspace.dataset,\n icon: workspace.icon,\n name: workspace.name,\n projectId: workspace.projectId,\n schemaDescriptorId: workspace.schemaDescriptorId,\n subtitle: workspace.subtitle,\n title: workspace.title,\n }))\n}\n\n/** Renders the workbench studio's deploy result; the appId hint shows only when none is configured. */\nfunction logWorkbenchStudioDeployed({\n applicationId,\n cliConfig,\n output,\n url,\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n output: DeployAppOptions['output']\n url: string\n}): void {\n output.log(`\\nSuccess! Studio deployed to ${styleText('cyan', url)}`)\n if (getAppId(cliConfig)) return\n\n output.log(`\\nAdd ${styleText('cyan', `appId: '${applicationId}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n}\n\nfunction studioBuildSkipReason({build, isExternal}: {build: boolean; isExternal: boolean}) {\n if (isExternal) return 'Build skipped for externally hosted studios'\n if (!build) return 'Build skipped (--no-build) — validating existing output directory'\n return\n}\n"],"names":["basename","dirname","styleText","createGzip","formatSchemaValidation","SchemaExtractionError","readIconFromPath","exitCodes","spinner","createStudio","deployWorkbenchApp","getApplicationUrl","getWorkbench","toWorkbenchPayload","c","createTar","createDeployment","getAppId","NO_ORGANIZATION_ID","NO_PROJECT_ID","buildStudio","createStudioUserApplication","checkAutoUpdates","checkBuild","checkPackageVersion","checkStudioTarget","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","deployStudioSchemasAndManifests","findUserApplicationForStudio","STUDIO_PACKAGE","deployStudio","options","listFiles","flags","projectRoot","sourceDir","external","Promise","resolve","directory","run","runStudioDeployment","type","reporter","cliConfig","output","workDir","isExternal","workbench","isWorkbenchApp","projectId","api","organizationId","app","appId","dryRun","report","exitCode","USAGE_ERROR","message","solution","status","appTitle","title","trim","slug","isAutoUpdating","version","moduleName","application","studioCreated","workbenchApp","created","resolveStudioApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","name","visibility","id","rollback","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","studioBuildSkipReason","successMessage","interfaces","payload","studioManifest","uploadStudioSchema","access","toAccess","isApp","label","onDeployed","workspaces","toWorkspaces","url","logWorkbenchStudioDeployed","action","location","shipStudioDeployment","err","studioHost","urlFlag","unattended","yes","log","registered","urlType","configPath","path","outPath","schemaRequired","verbose","error","validation","length","exit","RUNTIME_ERROR","tarball","cwd","pipe","spin","start","manifest","fail","succeed","named","example","resourceIds","Set","map","w","dataset","resourceId","resourceType","workspace","basePath","schemaDescriptorId","subtitle"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployStudio.ts"],"sourcesContent":["import {basename, dirname, relative} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip, type Gzip} from 'node:zlib'\n\nimport {formatSchemaValidation, SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {readIconFromPath} from '@sanity/cli-build/_internal/manifest'\nimport {exitCodes} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n type BrettAccess,\n type BrettWorkspace,\n createStudio,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {type StudioManifest} from 'sanity'\nimport {c as createTar} from 'tar'\n\nimport {createDeployment, type UserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {NO_ORGANIZATION_ID, NO_PROJECT_ID} from '../../util/errorMessages.js'\nimport {buildStudio} from '../build/buildStudio.js'\nimport {createStudioUserApplication} from './createUserApplication.js'\nimport {\n checkAutoUpdates,\n checkBuild,\n checkExternalUrl,\n checkPackageVersion,\n checkStudioTarget,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {deployStudioSchemasAndManifests} from './deployStudioSchemasAndManifests.js'\nimport {findUserApplicationForStudio} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst STUDIO_PACKAGE = 'sanity'\n\nexport function deployStudio(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({flags, projectRoot, sourceDir}) =>\n flags.external ? Promise.resolve([]) : listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runStudioDeployment,\n type: 'studio',\n })\n}\n\n/** Validates the deploy, extracts and uploads the schema, and ships the build. */\nasync function runStudioDeployment(\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 isExternal = !!flags.external\n const workbench = getWorkbench(cliConfig)\n const isWorkbenchApp = workbench !== null\n const projectId = cliConfig.api?.projectId\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const dryRun = !!flags['dry-run']\n // A legacy external studio only registers its URL; a federated one is built\n // and deployed like a hosted one, minus the upload.\n const isLegacyExternal = isExternal && !isWorkbenchApp\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n const version = await checkPackageVersion(reporter, {\n moduleName: STUDIO_PACKAGE,\n workDir,\n })\n\n reporter.report(\n projectId\n ? {message: `Project: ${projectId}`, status: 'pass'}\n : {\n message: NO_PROJECT_ID,\n solution: 'Add `api.projectId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n // Workbench studios deploy to Brett (which needs the org); plain studios\n // resolve/create on user-applications, unchanged.\n let application: UserApplication | null = null\n let studioCreated = false\n let workbenchApp: {externalUrl?: string} | undefined\n let externalUrl: string | undefined\n if (workbench) {\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 workbenchApp = (\n await checkStudioTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n if (isExternal) externalUrl = checkExternalUrl(reporter, {appId, url: flags.url})\n } else {\n ;({application, created: studioCreated} = await resolveStudioApplication(options, {\n dryRun,\n reporter,\n }))\n }\n // A redeploy follows how the application was registered, so --external is only needed once.\n const isExternallyHosted = isExternal || !!workbenchApp?.externalUrl\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 (workbench && !appId && !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 studio 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 && workbench && organizationId && !applicationId) {\n const created = await createStudio({\n externalUrl,\n name: workbench.name,\n organizationId,\n projectId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\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 buildStudio({\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: studioBuildSkipReason({build: flags.build, isLegacyExternal}),\n successMessage: 'Studio built',\n })\n\n if (!isLegacyExternal) {\n await verifyOutputDir({isWorkbenchApp, reporter, sourceDir})\n }\n\n const interfaces = workbench ? reportInterfaces(reporter, workbench) : null\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n ...(projectId ? {projectId} : {}),\n type: 'studio',\n version,\n ...toWorkbenchPayload(workbench, {interfaces, title: appTitle}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved version means the deploy target was never resolved.\n if (!version) return\n\n const studioManifest = await uploadStudioSchema(options, {\n applicationId: workbench ? applicationId : undefined,\n isExternal: isLegacyExternal,\n })\n // The studio was created (or resolved from `deployment.appId`) before the\n // build, so this only ships the deployment; plain studios use user-applications.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n access: toAccess(studioManifest),\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: false,\n isAutoUpdating,\n isExternal: isExternallyHosted,\n label: 'Deploying studio',\n // Once the deployment is live, a metadata-sync failure must not delete\n // the studio.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n workspaces: toWorkspaces(studioManifest),\n })\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'studio'})\n logWorkbenchStudioDeployed({applicationId, cliConfig, output, url})\n if (isExternallyHosted)\n logExternalHost({built: flags.build, organizationId, output, sourceDir})\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n if (!application) return\n const location = await shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n })\n\n return {\n action: studioCreated ? 'create' : 'update',\n application,\n payload,\n url: location,\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, registering a studio host when\n * none is configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveStudioApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplication | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const isExternal = !!flags.external\n const appId = getAppId(cliConfig)\n // Sets the title on a newly registered studio; blank falls back to undefined\n const title = flags.title?.trim() || undefined\n\n if (dryRun) {\n await checkStudioTarget(reporter, {\n appId,\n isExternal,\n projectId: cliConfig.api?.projectId,\n studioHost: cliConfig.studioHost,\n title,\n urlFlag: flags.url,\n })\n return {application: null, created: false}\n }\n\n const projectId = cliConfig.api?.projectId ?? ''\n // `created` is true when a configured-but-unregistered host was just registered.\n const {application, created} = await findUserApplicationForStudio({\n appId,\n isExternal,\n output,\n projectId,\n studioHost: cliConfig.studioHost,\n title,\n unattended: !!flags.yes,\n urlFlag: flags.url,\n })\n\n if (!application) {\n if (isExternal) {\n output.log('Your project has not been registered with an external studio URL.')\n output.log('Please enter the full URL where your studio is hosted.')\n } else {\n output.log('Your project has not been assigned a studio hostname.')\n output.log('To deploy your Sanity Studio to our hosted sanity.studio service,')\n output.log('you will need one. Please enter the subdomain you want to use.')\n }\n\n const registered = await createStudioUserApplication({\n projectId,\n title,\n urlType: isExternal ? 'external' : 'internal',\n })\n deployDebug('Created user application', registered)\n return {application: registered, created: true}\n }\n\n deployDebug('Found user application', application)\n return {application, created}\n}\n\n/** Extracts the studio schema and manifest and uploads them to the schema store. */\nasync function uploadStudioSchema(\n options: DeployAppOptions,\n {applicationId, isExternal}: {applicationId?: string; isExternal: boolean},\n): Promise<StudioManifest | null> {\n const {cliConfig, flags, output, projectRoot, sourceDir} = options\n\n let studioManifest: StudioManifest | null = null\n try {\n studioManifest = await deployStudioSchemasAndManifests(\n {\n applicationId,\n configPath: projectRoot.path,\n isExternal,\n outPath: `${sourceDir}/static`,\n projectId: cliConfig.api?.projectId ?? '',\n schemaRequired: flags['schema-required'],\n verbose: flags.verbose,\n workDir: projectRoot.directory,\n },\n output,\n )\n } catch (error) {\n deployDebug('Error deploying studio schemas and manifests', error)\n if (error instanceof SchemaExtractionError && error.validation?.length) {\n output.error(formatSchemaValidation(error.validation), {exit: exitCodes.RUNTIME_ERROR})\n }\n output.error(`Error deploying studio schemas and manifests: ${error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!studioManifest) {\n output.error('Failed to generate studio manifest. Please check your schemas and manifests.', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n return studioManifest\n}\n\nasync function shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n isExternal: boolean\n options: DeployAppOptions\n studioManifest: StudioManifest | null\n version: string\n}): Promise<string> {\n const {cliConfig, output, sourceDir} = options\n\n let tarball: Gzip | undefined\n if (!isExternal) {\n tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n }\n\n const spin = spinner(isExternal ? 'Registering studio' : 'Deploying to sanity.studio').start()\n let location: string\n try {\n ;({location} = await createDeployment({\n applicationId: application.id,\n isApp: false,\n isAutoUpdating,\n manifest: studioManifest,\n projectId: cliConfig.api?.projectId,\n tarball,\n version,\n }))\n } catch (error) {\n spin.fail()\n throw error\n }\n spin.succeed()\n\n const named = application.title ? ` — \"${application.title}\"` : ''\n output.log(\n isExternal\n ? `\\nSuccess! Studio registered${named}`\n : `\\nSuccess! Studio deployed to ${styleText('cyan', location)}${named}`,\n )\n\n if (getAppId(cliConfig)) return location\n\n const example = `Example:\nexport default defineCliConfig({\n //…\n deployment: {\n ${styleText('cyan', `appId: '${application.id}'`)},\n },\n //…\n})`\n output.log(`\\nAdd ${styleText('cyan', `appId: '${application.id}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n output.log(`\\n${example}`)\n\n return location\n}\n\n/**\n * One `datasets` access entry per unique workspace dataset, with a `resourceId`\n * of `\"<projectId>.<dataset>\"`. Deduped, since workspaces can share a dataset.\n */\nfunction toAccess(manifest: StudioManifest | null): BrettAccess[] {\n const resourceIds = new Set(\n (manifest?.workspaces ?? []).map((w) => `${w.projectId}.${w.dataset}`),\n )\n return [...resourceIds].map(\n (resourceId) => ({resourceId, resourceType: 'dataset'}) satisfies BrettAccess,\n )\n}\n\nfunction toWorkspaces(manifest: StudioManifest | null): BrettWorkspace[] {\n return (manifest?.workspaces ?? []).map((workspace) => ({\n basePath: workspace.basePath,\n dataset: workspace.dataset,\n icon: workspace.icon,\n name: workspace.name,\n projectId: workspace.projectId,\n schemaDescriptorId: workspace.schemaDescriptorId,\n subtitle: workspace.subtitle,\n title: workspace.title,\n }))\n}\n\n/** Renders the workbench studio's deploy result; the appId hint shows only when none is configured. */\nfunction logWorkbenchStudioDeployed({\n applicationId,\n cliConfig,\n output,\n url,\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n output: DeployAppOptions['output']\n url: string\n}): void {\n output.log(`\\nSuccess! Studio deployed to ${styleText('cyan', url)}`)\n if (getAppId(cliConfig)) return\n\n output.log(`\\nAdd ${styleText('cyan', `appId: '${applicationId}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n}\n\n/** Tells the customer what their host must do for the Dashboard to load the studio from it. */\nfunction logExternalHost({\n built,\n organizationId,\n output,\n sourceDir,\n}: {\n built: boolean\n organizationId: string\n output: DeployAppOptions['output']\n sourceDir: string\n}): void {\n const dir = `${relative(process.cwd(), sourceDir) || '.'}/`\n output.log(`\nThe Dashboard loads this studio from your host, which must:\n 1. Serve ${dir} unchanged at the root of its URL (/mf-manifest.json, /remoteEntry-*.js, /static/*)\n 2. Send Access-Control-Allow-Origin for ${getWorkbenchUrl(organizationId)}\n 3. Respond without cookies or a sign-in${built ? `\\n\\nThis deploy rebuilt ${dir}: copy it to your host before opening the studio in the Dashboard.` : ''}`)\n}\n\nfunction studioBuildSkipReason({\n build,\n isLegacyExternal,\n}: {\n build: boolean\n isLegacyExternal: boolean\n}) {\n if (isLegacyExternal) return 'Build skipped for externally hosted studios'\n if (!build) return 'Build skipped (--no-build) — validating existing output directory'\n return\n}\n"],"names":["basename","dirname","relative","styleText","createGzip","formatSchemaValidation","SchemaExtractionError","readIconFromPath","exitCodes","spinner","createStudio","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","toWorkbenchPayload","c","createTar","createDeployment","getAppId","NO_ORGANIZATION_ID","NO_PROJECT_ID","buildStudio","createStudioUserApplication","checkAutoUpdates","checkBuild","checkExternalUrl","checkPackageVersion","checkStudioTarget","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","deployStudioSchemasAndManifests","findUserApplicationForStudio","STUDIO_PACKAGE","deployStudio","options","listFiles","flags","projectRoot","sourceDir","external","Promise","resolve","directory","run","runStudioDeployment","type","reporter","cliConfig","output","workDir","isExternal","workbench","isWorkbenchApp","projectId","api","organizationId","app","appId","dryRun","isLegacyExternal","appTitle","title","trim","slug","isAutoUpdating","version","moduleName","report","message","status","solution","application","studioCreated","workbenchApp","externalUrl","url","created","resolveStudioApplication","isExternallyHosted","build","exitCode","USAGE_ERROR","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","name","visibility","id","rollback","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","studioBuildSkipReason","successMessage","interfaces","payload","studioManifest","uploadStudioSchema","access","toAccess","isApp","label","onDeployed","workspaces","toWorkspaces","logWorkbenchStudioDeployed","logExternalHost","built","action","location","shipStudioDeployment","err","studioHost","urlFlag","unattended","yes","log","registered","urlType","configPath","path","outPath","schemaRequired","verbose","error","validation","length","exit","RUNTIME_ERROR","tarball","cwd","pipe","spin","start","manifest","fail","succeed","named","example","resourceIds","Set","map","w","dataset","resourceId","resourceType","workspace","basePath","schemaDescriptorId","subtitle","dir","process"],"mappings":"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"}