@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 +41 -6
- package/dist/actions/deploy/deployChecks.js +44 -1
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +40 -25
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/typegen/fetchResourceSchema.js +40 -0
- package/dist/actions/typegen/fetchResourceSchema.js.map +1 -0
- package/dist/actions/typegen/generateResourceTypes.js +115 -0
- package/dist/actions/typegen/generateResourceTypes.js.map +1 -0
- package/dist/actions/typegen/parseTypegenResources.js +92 -0
- package/dist/actions/typegen/parseTypegenResources.js.map +1 -0
- package/dist/commands/deploy.js +6 -3
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/typegen/generate.js +59 -5
- package/dist/commands/typegen/generate.js.map +1 -1
- package/dist/exports/runtime.d.ts +2 -2
- package/dist/exports/runtime.js.map +1 -1
- package/dist/server/vite/plugin-typegen.js +10 -0
- package/dist/server/vite/plugin-typegen.js.map +1 -1
- package/dist/services/schemas.js +36 -0
- package/dist/services/schemas.js.map +1 -1
- package/oclif.manifest.json +1694 -1691
- package/package.json +6 -5
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
|
40
|
-
//
|
|
41
|
-
|
|
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
|
-
|
|
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 && !
|
|
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 &&
|
|
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 &&
|
|
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
|
-
|
|
142
|
+
isLegacyExternal
|
|
142
143
|
}),
|
|
143
144
|
successMessage: 'Studio built'
|
|
144
145
|
});
|
|
145
|
-
if (!
|
|
146
|
+
if (!isLegacyExternal) {
|
|
146
147
|
await verifyOutputDir({
|
|
147
148
|
isWorkbenchApp,
|
|
148
149
|
reporter,
|
|
149
150
|
sourceDir
|
|
150
151
|
});
|
|
151
152
|
}
|
|
152
|
-
|
|
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 &&
|
|
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
|
|
413
|
-
|
|
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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"}
|