@sanity/cli 8.22.0 → 8.23.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.
Files changed (89) hide show
  1. package/dist/actions/context/watchJob.js +9 -3
  2. package/dist/actions/context/watchJob.js.map +1 -1
  3. package/dist/actions/deploy/blueprintManaged.js +59 -0
  4. package/dist/actions/deploy/blueprintManaged.js.map +1 -0
  5. package/dist/actions/deploy/deployApp.js +117 -1
  6. package/dist/actions/deploy/deployApp.js.map +1 -1
  7. package/dist/actions/deploy/deployRunner.js.map +1 -1
  8. package/dist/actions/deploy/deployStudio.js +6 -31
  9. package/dist/actions/deploy/deployStudio.js.map +1 -1
  10. package/dist/actions/deploy/deployStudioSchemasAndManifestsWorker.js +6 -15
  11. package/dist/actions/deploy/deployStudioSchemasAndManifestsWorker.js.map +1 -1
  12. package/dist/actions/exec/runScript.worker.js +6 -2
  13. package/dist/actions/exec/runScript.worker.js.map +1 -1
  14. package/dist/actions/init/bootstrapLocalTemplate.js +35 -11
  15. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  16. package/dist/actions/init/createMediaLibraryCliConfig.js +12 -0
  17. package/dist/actions/init/createMediaLibraryCliConfig.js.map +1 -0
  18. package/dist/actions/init/determineMediaLibraryTemplate.js +14 -0
  19. package/dist/actions/init/determineMediaLibraryTemplate.js.map +1 -0
  20. package/dist/actions/init/initAction.js +35 -6
  21. package/dist/actions/init/initAction.js.map +1 -1
  22. package/dist/actions/init/initApp.js +81 -6
  23. package/dist/actions/init/initApp.js.map +1 -1
  24. package/dist/actions/init/offerAspectPull.js +81 -0
  25. package/dist/actions/init/offerAspectPull.js.map +1 -0
  26. package/dist/actions/init/project/getProjectDetails.js +25 -2
  27. package/dist/actions/init/project/getProjectDetails.js.map +1 -1
  28. package/dist/actions/init/templates/index.js +3 -0
  29. package/dist/actions/init/templates/index.js.map +1 -1
  30. package/dist/actions/init/templates/mediaLibraryConfig.js +51 -0
  31. package/dist/actions/init/templates/mediaLibraryConfig.js.map +1 -0
  32. package/dist/actions/media/aspectName.js +8 -0
  33. package/dist/actions/media/aspectName.js.map +1 -0
  34. package/dist/actions/media/aspectSync/contract.js +163 -0
  35. package/dist/actions/media/aspectSync/contract.js.map +1 -0
  36. package/dist/actions/media/aspectSync/syncAspects.js +115 -0
  37. package/dist/actions/media/aspectSync/syncAspects.js.map +1 -0
  38. package/dist/actions/media/cliConfigFields.js +192 -0
  39. package/dist/actions/media/cliConfigFields.js.map +1 -0
  40. package/dist/actions/media/pullAspects.js +225 -0
  41. package/dist/actions/media/pullAspects.js.map +1 -0
  42. package/dist/actions/media/resolveMediaLibraryId.js +83 -0
  43. package/dist/actions/media/resolveMediaLibraryId.js.map +1 -0
  44. package/dist/actions/schema/deploySchemas.js.map +1 -1
  45. package/dist/actions/schema/extractSchemaWatcher.js +69 -14
  46. package/dist/actions/schema/extractSchemaWatcher.js.map +1 -1
  47. package/dist/actions/schema/updateWorkspaceSchema.js.map +1 -1
  48. package/dist/commands/context/build.js +2 -2
  49. package/dist/commands/context/build.js.map +1 -1
  50. package/dist/commands/context/entries/get.js +83 -0
  51. package/dist/commands/context/entries/get.js.map +1 -0
  52. package/dist/commands/context/entries/list.js +82 -0
  53. package/dist/commands/context/entries/list.js.map +1 -0
  54. package/dist/commands/context/entries/rebuild.js +95 -0
  55. package/dist/commands/context/entries/rebuild.js.map +1 -0
  56. package/dist/commands/context/issues/apply.js +86 -0
  57. package/dist/commands/context/issues/apply.js.map +1 -0
  58. package/dist/commands/context/issues/dismiss.js +52 -0
  59. package/dist/commands/context/issues/dismiss.js.map +1 -0
  60. package/dist/commands/context/issues/get.js +105 -0
  61. package/dist/commands/context/issues/get.js.map +1 -0
  62. package/dist/commands/context/issues/list.js +128 -0
  63. package/dist/commands/context/issues/list.js.map +1 -0
  64. package/dist/commands/context/issues/reopen.js +53 -0
  65. package/dist/commands/context/issues/reopen.js.map +1 -0
  66. package/dist/commands/context/issues/resolve.js +137 -0
  67. package/dist/commands/context/issues/resolve.js.map +1 -0
  68. package/dist/commands/context/jobs/get.js +2 -2
  69. package/dist/commands/context/jobs/get.js.map +1 -1
  70. package/dist/commands/context/query.js +92 -0
  71. package/dist/commands/context/query.js.map +1 -0
  72. package/dist/commands/deploy.js +13 -0
  73. package/dist/commands/deploy.js.map +1 -1
  74. package/dist/commands/media/prune-aspect-data.js +170 -0
  75. package/dist/commands/media/prune-aspect-data.js.map +1 -0
  76. package/dist/commands/media/pull-aspects.js +309 -0
  77. package/dist/commands/media/pull-aspects.js.map +1 -0
  78. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +17 -0
  79. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  80. package/dist/services/context.js +96 -3
  81. package/dist/services/context.js.map +1 -1
  82. package/dist/services/mediaLibraries.js +175 -8
  83. package/dist/services/mediaLibraries.js.map +1 -1
  84. package/oclif.manifest.json +1050 -361
  85. package/package.json +6 -5
  86. package/templates/media-library-config/README.md +52 -0
  87. package/templates/media-library-config/eslint.config.txt +52 -0
  88. package/templates/media-library-config/src/fields/caption.tsx +29 -0
  89. package/templates/media-library-config/src/fields/notes.tsx +54 -0
@@ -1,5 +1,11 @@
1
1
  import { spinner } from '@sanity/cli-core/ux';
2
2
  import { waitForJob } from './waitForJob.js';
3
+ /**
4
+ * Error message for a job that ended in a non-succeeded terminal state,
5
+ * e.g. "Build failed: <reason>"
6
+ */ export function formatJobFailure(noun, job) {
7
+ return `${noun} ${job.status}${job.error ? `: ${job.error}` : ''}`;
8
+ }
3
9
  /**
4
10
  * Watch a knowledge base job with a spinner until it reaches a terminal
5
11
  * state, updating the spinner text with the job status on each poll.
@@ -18,13 +24,13 @@ import { waitForJob } from './waitForJob.js';
18
24
  }
19
25
  });
20
26
  } catch (error) {
21
- spin.fail();
27
+ spin.fail(label);
22
28
  throw error;
23
29
  }
24
30
  if (job.status === 'succeeded') {
25
- spin.succeed(successText);
31
+ spin.succeed(successText ?? label);
26
32
  } else {
27
- spin.fail();
33
+ spin.fail(label);
28
34
  }
29
35
  return job;
30
36
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/context/watchJob.ts"],"sourcesContent":["import {spinner} from '@sanity/cli-core/ux'\nimport {type Context} from '@sanity/client'\n\nimport {waitForJob} from './waitForJob.js'\n\n/**\n * Watch a knowledge base job with a spinner until it reaches a terminal\n * state, updating the spinner text with the job status on each poll.\n *\n * Fails the spinner and rethrows on polling errors, and fails it when the\n * terminal status is not `succeeded` — turning either outcome into a\n * command error (and exit code) is the caller's responsibility.\n */\nexport async function watchJob(\n knowledgeBaseId: string,\n jobId: string,\n options: {label: string; successText?: string},\n): Promise<Context.Job> {\n const {label, successText} = options\n const spin = spinner(label).start()\n\n let job: Context.Job\n try {\n job = await waitForJob(knowledgeBaseId, jobId, {\n onPoll: (pending) => {\n spin.text = `${label} (${pending.status})`\n },\n })\n } catch (error) {\n spin.fail()\n throw error\n }\n\n if (job.status === 'succeeded') {\n spin.succeed(successText)\n } else {\n spin.fail()\n }\n\n return job\n}\n"],"names":["spinner","waitForJob","watchJob","knowledgeBaseId","jobId","options","label","successText","spin","start","job","onPoll","pending","text","status","error","fail","succeed"],"mappings":"AAAA,SAAQA,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,UAAU,QAAO,kBAAiB;AAE1C;;;;;;;CAOC,GACD,OAAO,eAAeC,SACpBC,eAAuB,EACvBC,KAAa,EACbC,OAA8C;IAE9C,MAAM,EAACC,KAAK,EAAEC,WAAW,EAAC,GAAGF;IAC7B,MAAMG,OAAOR,QAAQM,OAAOG,KAAK;IAEjC,IAAIC;IACJ,IAAI;QACFA,MAAM,MAAMT,WAAWE,iBAAiBC,OAAO;YAC7CO,QAAQ,CAACC;gBACPJ,KAAKK,IAAI,GAAG,GAAGP,MAAM,EAAE,EAAEM,QAAQE,MAAM,CAAC,CAAC,CAAC;YAC5C;QACF;IACF,EAAE,OAAOC,OAAO;QACdP,KAAKQ,IAAI;QACT,MAAMD;IACR;IAEA,IAAIL,IAAII,MAAM,KAAK,aAAa;QAC9BN,KAAKS,OAAO,CAACV;IACf,OAAO;QACLC,KAAKQ,IAAI;IACX;IAEA,OAAON;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/context/watchJob.ts"],"sourcesContent":["import {spinner} from '@sanity/cli-core/ux'\nimport {type Context} from '@sanity/client'\n\nimport {waitForJob} from './waitForJob.js'\n\n/**\n * Error message for a job that ended in a non-succeeded terminal state,\n * e.g. \"Build failed: <reason>\"\n */\nexport function formatJobFailure(noun: string, job: Context.Job): string {\n return `${noun} ${job.status}${job.error ? `: ${job.error}` : ''}`\n}\n\n/**\n * Watch a knowledge base job with a spinner until it reaches a terminal\n * state, updating the spinner text with the job status on each poll.\n *\n * Fails the spinner and rethrows on polling errors, and fails it when the\n * terminal status is not `succeeded` — turning either outcome into a\n * command error (and exit code) is the caller's responsibility.\n */\nexport async function watchJob(\n knowledgeBaseId: string,\n jobId: string,\n options: {label: string; successText?: string},\n): Promise<Context.Job> {\n const {label, successText} = options\n const spin = spinner(label).start()\n\n let job: Context.Job\n try {\n job = await waitForJob(knowledgeBaseId, jobId, {\n onPoll: (pending) => {\n spin.text = `${label} (${pending.status})`\n },\n })\n } catch (error) {\n spin.fail(label)\n throw error\n }\n\n if (job.status === 'succeeded') {\n spin.succeed(successText ?? label)\n } else {\n spin.fail(label)\n }\n\n return job\n}\n"],"names":["spinner","waitForJob","formatJobFailure","noun","job","status","error","watchJob","knowledgeBaseId","jobId","options","label","successText","spin","start","onPoll","pending","text","fail","succeed"],"mappings":"AAAA,SAAQA,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,UAAU,QAAO,kBAAiB;AAE1C;;;CAGC,GACD,OAAO,SAASC,iBAAiBC,IAAY,EAAEC,GAAgB;IAC7D,OAAO,GAAGD,KAAK,CAAC,EAAEC,IAAIC,MAAM,GAAGD,IAAIE,KAAK,GAAG,CAAC,EAAE,EAAEF,IAAIE,KAAK,EAAE,GAAG,IAAI;AACpE;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeC,SACpBC,eAAuB,EACvBC,KAAa,EACbC,OAA8C;IAE9C,MAAM,EAACC,KAAK,EAAEC,WAAW,EAAC,GAAGF;IAC7B,MAAMG,OAAOb,QAAQW,OAAOG,KAAK;IAEjC,IAAIV;IACJ,IAAI;QACFA,MAAM,MAAMH,WAAWO,iBAAiBC,OAAO;YAC7CM,QAAQ,CAACC;gBACPH,KAAKI,IAAI,GAAG,GAAGN,MAAM,EAAE,EAAEK,QAAQX,MAAM,CAAC,CAAC,CAAC;YAC5C;QACF;IACF,EAAE,OAAOC,OAAO;QACdO,KAAKK,IAAI,CAACP;QACV,MAAML;IACR;IAEA,IAAIF,IAAIC,MAAM,KAAK,aAAa;QAC9BQ,KAAKM,OAAO,CAACP,eAAeD;IAC9B,OAAO;QACLE,KAAKK,IAAI,CAACP;IACZ;IAEA,OAAOP;AACT"}
@@ -0,0 +1,59 @@
1
+ import { dirname, join, relative } from 'node:path';
2
+ import { findBlueprintFile, readBlueprint } from '@sanity/blueprints/resolve';
3
+ import { deployDebug } from './deployDebug.js';
4
+ /**
5
+ * The blueprint resource types a `deploy` can collide with, and the article the
6
+ * message needs so both "a studio" and "an app" read naturally.
7
+ */ const RESOURCES = {
8
+ coreApp: {
9
+ article: 'an',
10
+ noun: 'app',
11
+ type: 'sanity.application'
12
+ },
13
+ studio: {
14
+ article: 'a',
15
+ noun: 'studio',
16
+ type: 'sanity.studio'
17
+ }
18
+ };
19
+ /**
20
+ * A blueprint owns the deploys of the resources it declares, so the `deploy`
21
+ * command must not ship one behind its back — the two would write the same
22
+ * application from different sources of truth.
23
+ *
24
+ * Reports a `fail` when the directory being deployed is the root of a `kind`
25
+ * resource in the blueprint next to it, which a real run exits on.
26
+ */ export async function checkBlueprintManaged(reporter, { kind, projectRootDir }) {
27
+ if (!await isBlueprintManaged(kind, projectRootDir)) return;
28
+ const { article, noun } = RESOURCES[kind];
29
+ reporter.report({
30
+ message: `Using the \`deploy\` command for ${article} ${noun} that is referenced by a blueprint is not allowed`,
31
+ solution: `Deploy the ${noun} using the \`blueprints deploy\` command`,
32
+ status: 'fail'
33
+ });
34
+ }
35
+ /**
36
+ * Determine if the directory being deployed is referenced by a blueprint.
37
+ * @param kind - The kind of resource being deployed
38
+ * @param projectRootDir - The root directory of the studio or app
39
+ */ async function isBlueprintManaged(kind, projectRootDir) {
40
+ try {
41
+ const blueprintFile = findBlueprintFile(projectRootDir);
42
+ if (!blueprintFile) return false;
43
+ const localBlueprint = await readBlueprint({
44
+ path: blueprintFile
45
+ });
46
+ return localBlueprint.resources.some((r)=>{
47
+ if (r.type === RESOURCES[kind].type && 'root' in r && typeof r.root === 'string') {
48
+ return relative(join(dirname(blueprintFile), r.root), projectRootDir) === '';
49
+ }
50
+ return false;
51
+ });
52
+ } catch (err) {
53
+ deployDebug('Error resolving the blueprint next to the deploy', err);
54
+ return false // fail open
55
+ ;
56
+ }
57
+ }
58
+
59
+ //# sourceMappingURL=blueprintManaged.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/deploy/blueprintManaged.ts"],"sourcesContent":["import {dirname, join, relative} from 'node:path'\n\nimport {findBlueprintFile, readBlueprint} from '@sanity/blueprints/resolve'\n\nimport {type DeployCheckReporter} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\n\n/**\n * The blueprint resource types a `deploy` can collide with, and the article the\n * message needs so both \"a studio\" and \"an app\" read naturally.\n */\nconst RESOURCES = {\n coreApp: {article: 'an', noun: 'app', type: 'sanity.application'},\n studio: {article: 'a', noun: 'studio', type: 'sanity.studio'},\n} as const\n\ntype BlueprintManagedKind = keyof typeof RESOURCES\n\n/**\n * A blueprint owns the deploys of the resources it declares, so the `deploy`\n * command must not ship one behind its back — the two would write the same\n * application from different sources of truth.\n *\n * Reports a `fail` when the directory being deployed is the root of a `kind`\n * resource in the blueprint next to it, which a real run exits on.\n */\nexport async function checkBlueprintManaged(\n reporter: DeployCheckReporter,\n {kind, projectRootDir}: {kind: BlueprintManagedKind; projectRootDir: string},\n): Promise<void> {\n if (!(await isBlueprintManaged(kind, projectRootDir))) return\n\n const {article, noun} = RESOURCES[kind]\n reporter.report({\n message: `Using the \\`deploy\\` command for ${article} ${noun} that is referenced by a blueprint is not allowed`,\n solution: `Deploy the ${noun} using the \\`blueprints deploy\\` command`,\n status: 'fail',\n })\n}\n\n/**\n * Determine if the directory being deployed is referenced by a blueprint.\n * @param kind - The kind of resource being deployed\n * @param projectRootDir - The root directory of the studio or app\n */\nasync function isBlueprintManaged(\n kind: BlueprintManagedKind,\n projectRootDir: string,\n): Promise<boolean> {\n try {\n const blueprintFile = findBlueprintFile(projectRootDir)\n if (!blueprintFile) return false\n\n const localBlueprint = await readBlueprint({\n path: blueprintFile,\n })\n\n return localBlueprint.resources.some((r) => {\n if (r.type === RESOURCES[kind].type && 'root' in r && typeof r.root === 'string') {\n return relative(join(dirname(blueprintFile), r.root), projectRootDir) === ''\n }\n\n return false\n })\n } catch (err) {\n deployDebug('Error resolving the blueprint next to the deploy', err)\n return false // fail open\n }\n}\n"],"names":["dirname","join","relative","findBlueprintFile","readBlueprint","deployDebug","RESOURCES","coreApp","article","noun","type","studio","checkBlueprintManaged","reporter","kind","projectRootDir","isBlueprintManaged","report","message","solution","status","blueprintFile","localBlueprint","path","resources","some","r","root","err"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,IAAI,EAAEC,QAAQ,QAAO,YAAW;AAEjD,SAAQC,iBAAiB,EAAEC,aAAa,QAAO,6BAA4B;AAG3E,SAAQC,WAAW,QAAO,mBAAkB;AAE5C;;;CAGC,GACD,MAAMC,YAAY;IAChBC,SAAS;QAACC,SAAS;QAAMC,MAAM;QAAOC,MAAM;IAAoB;IAChEC,QAAQ;QAACH,SAAS;QAAKC,MAAM;QAAUC,MAAM;IAAe;AAC9D;AAIA;;;;;;;CAOC,GACD,OAAO,eAAeE,sBACpBC,QAA6B,EAC7B,EAACC,IAAI,EAAEC,cAAc,EAAuD;IAE5E,IAAI,CAAE,MAAMC,mBAAmBF,MAAMC,iBAAkB;IAEvD,MAAM,EAACP,OAAO,EAAEC,IAAI,EAAC,GAAGH,SAAS,CAACQ,KAAK;IACvCD,SAASI,MAAM,CAAC;QACdC,SAAS,CAAC,iCAAiC,EAAEV,QAAQ,CAAC,EAAEC,KAAK,iDAAiD,CAAC;QAC/GU,UAAU,CAAC,WAAW,EAAEV,KAAK,wCAAwC,CAAC;QACtEW,QAAQ;IACV;AACF;AAEA;;;;CAIC,GACD,eAAeJ,mBACbF,IAA0B,EAC1BC,cAAsB;IAEtB,IAAI;QACF,MAAMM,gBAAgBlB,kBAAkBY;QACxC,IAAI,CAACM,eAAe,OAAO;QAE3B,MAAMC,iBAAiB,MAAMlB,cAAc;YACzCmB,MAAMF;QACR;QAEA,OAAOC,eAAeE,SAAS,CAACC,IAAI,CAAC,CAACC;YACpC,IAAIA,EAAEhB,IAAI,KAAKJ,SAAS,CAACQ,KAAK,CAACJ,IAAI,IAAI,UAAUgB,KAAK,OAAOA,EAAEC,IAAI,KAAK,UAAU;gBAChF,OAAOzB,SAASD,KAAKD,QAAQqB,gBAAgBK,EAAEC,IAAI,GAAGZ,oBAAoB;YAC5E;YAEA,OAAO;QACT;IACF,EAAE,OAAOa,KAAK;QACZvB,YAAY,oDAAoDuB;QAChE,OAAO,MAAM,YAAY;;IAC3B;AACF"}
@@ -5,14 +5,18 @@ import { extractCoreAppManifest, readIconFromPath, resolveTitleUpdate } from '@s
5
5
  import { exitCodes } from '@sanity/cli-core';
6
6
  import { getErrorMessage } from '@sanity/cli-core/errors';
7
7
  import { getCoreAppUrl } from '@sanity/cli-core/util';
8
- import { spinner } from '@sanity/cli-core/ux';
8
+ import { confirm, spinner } from '@sanity/cli-core/ux';
9
9
  import { resolveAppEntry } from '@sanity/workbench-cli/build';
10
10
  import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
11
11
  import { c as createTar } from 'tar';
12
12
  import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
13
13
  import { getAppId } from '../../util/appId.js';
14
+ import { runStep } from '../../util/checks.js';
14
15
  import { EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID } from '../../util/errorMessages.js';
16
+ import { pluralize } from '../../util/pluralize.js';
15
17
  import { buildApp } from '../build/buildApp.js';
18
+ import { applyAspectSync, planAspectSync } from '../media/aspectSync/syncAspects.js';
19
+ import { checkBlueprintManaged } from './blueprintManaged.js';
16
20
  import { createUserApplication } from './createUserApplication.js';
17
21
  import { checkAppId, checkAppTarget, checkAutoUpdates, checkBuild, checkPackageVersion, verifyOutputDir } from './deployChecks.js';
18
22
  import { deployDebug } from './deployDebug.js';
@@ -94,6 +98,10 @@ export function deployApp(options) {
94
98
  checkAppId(reporter, {
95
99
  cliConfig
96
100
  });
101
+ await checkBlueprintManaged(reporter, {
102
+ kind: 'coreApp',
103
+ projectRootDir: workDir
104
+ });
97
105
  let application = null;
98
106
  let appCreated = false;
99
107
  let workbenchApp;
@@ -211,6 +219,42 @@ export function deployApp(options) {
211
219
  status: 'fail'
212
220
  });
213
221
  }
222
+ // Plan the aspect-document sync in both modes, so the report — dry-run and
223
+ // real — shows what the sync will write and, prominently, what it will
224
+ // delete, before anything mutates. Gated on a resolved installation: when
225
+ // that check failed, a real run already exited and a dry run has reported
226
+ // the config as undeployable.
227
+ let aspectSyncPlan;
228
+ // Gated on the `appType` discriminator, not the mere presence of a config:
229
+ // `ConfigSchema` is a union built to grow, and a future config type must
230
+ // not inherit the media-library aspect sync — and its deletions — by
231
+ // default.
232
+ if (configAppType === 'media-library' && organizationId && config && installationId) {
233
+ // runStep so an unexpected throw (network, API) becomes a fail check:
234
+ // a real run exits, a dry run records it and keeps reporting.
235
+ const planned = await runStep(reporter, {
236
+ debug: deployDebug,
237
+ formatError: (err)=>`Planning the aspect-document sync failed: ${getErrorMessage(err)}`,
238
+ name: 'aspect sync plan',
239
+ work: ()=>planAspectSync({
240
+ fields: config.fields,
241
+ mediaLibraryId: flags['media-library-id'],
242
+ organizationId,
243
+ workDir
244
+ })
245
+ });
246
+ if (planned && 'failure' in planned) {
247
+ reporter.report({
248
+ exitCode: planned.failure.exitCode,
249
+ message: planned.failure.message,
250
+ solution: planned.failure.solution,
251
+ status: 'fail'
252
+ });
253
+ } else if (planned) {
254
+ aspectSyncPlan = planned.plan;
255
+ reportAspectSyncPlan(reporter, aspectSyncPlan);
256
+ }
257
+ }
214
258
  const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null;
215
259
  // Applied after the app is live (see below) so a failed deploy never leaves
216
260
  // the org's installation config without its application.
@@ -241,6 +285,13 @@ export function deployApp(options) {
241
285
  }),
242
286
  ...configSummary ? {
243
287
  config: configSummary
288
+ } : {},
289
+ ...aspectSyncPlan ? {
290
+ aspectSync: {
291
+ deleteIds: aspectSyncPlan.staleIds,
292
+ mediaLibraryId: aspectSyncPlan.mediaLibraryId,
293
+ upsertIds: aspectSyncPlan.documents.map((document)=>document._id)
294
+ }
244
295
  } : {}
245
296
  };
246
297
  // Dry run stops here — everything below mutates.
@@ -248,9 +299,28 @@ export function deployApp(options) {
248
299
  application: null,
249
300
  payload
250
301
  };
302
+ // Deleting stored definitions is the destructive part of a config deploy,
303
+ // so an interactive run confirms it before anything mutates. Unattended
304
+ // runs (--yes; forced in CI) proceed — the config is the source of truth
305
+ // and the dry-run report lists the deletions.
306
+ if (aspectSyncPlan && aspectSyncPlan.staleIds.length > 0 && !flags.yes) {
307
+ const staleCount = aspectSyncPlan.staleIds.length;
308
+ const proceed = await confirm({
309
+ default: false,
310
+ message: `Delete ${staleCount} stored aspect ${pluralize('definition', staleCount)} with no ` + `matching config field (${aspectSyncPlan.staleIds.join(', ')})?`
311
+ });
312
+ if (!proceed) {
313
+ output.error('Deploy cancelled — the stored aspect definitions are unchanged.', {
314
+ exit: exitCodes.USER_ABORT
315
+ });
316
+ }
317
+ }
251
318
  // A config-only singleton ships no application, only its config.
252
319
  if (!deployApplication) {
253
320
  await deployApplicationConfig();
321
+ if (aspectSyncPlan) {
322
+ await runAspectSync(aspectSyncPlan, output);
323
+ }
254
324
  if (installationId && version) {
255
325
  return {
256
326
  application: null,
@@ -343,6 +413,52 @@ export function deployApp(options) {
343
413
  throw err;
344
414
  }
345
415
  }
416
+ /**
417
+ * Reports the planned aspect-document sync: the upserts as a pass, stripped
418
+ * non-serializable values as information, and — prominently, as a warning —
419
+ * the stored definitions the sync will delete because no config field matches
420
+ * them. Deploy is a mirror: the config owns the library's aspect namespace.
421
+ */ export function reportAspectSyncPlan(reporter, plan) {
422
+ const upserts = plan.documents.length;
423
+ reporter.report({
424
+ message: `Will sync ${upserts} aspect ${pluralize('definition', upserts)} to media library ${plan.mediaLibraryId}`,
425
+ status: 'pass'
426
+ });
427
+ const strippedFields = Object.entries(plan.strippedByField);
428
+ if (strippedFields.length > 0) {
429
+ // Expected for fields with custom inputs, validation callbacks, or
430
+ // initial-value resolvers: the live config keeps those capabilities, only
431
+ // the stored mirror (read by Studio plugin mode and the dashboard) omits
432
+ // them. Reported so the capability gap is explicit, but not a warning.
433
+ const details = strippedFields.map(([name, paths])=>`${name} (${paths.join(', ')})`).join('; ');
434
+ reporter.report({
435
+ message: `Stored definitions omit non-serializable values: ${details}`,
436
+ status: 'pass'
437
+ });
438
+ }
439
+ if (plan.staleIds.length > 0) {
440
+ reporter.report({
441
+ message: `Will delete ${plan.staleIds.length} stored aspect ${pluralize('definition', plan.staleIds.length)} with no matching config field: ${plan.staleIds.join(', ')}`,
442
+ solution: 'Definitions only — aspects.<name> values on assets stay put and resurface if a matching ' + 'field is added back. To keep a definition, declare a matching field in sanity.cli.ts ' + '(generate one with `sanity media pull-aspects`)',
443
+ status: 'warn'
444
+ });
445
+ }
446
+ }
447
+ /**
448
+ * Applies the planned sync after the config itself deployed. A failure here
449
+ * leaves the config live but the stored mirror stale, so the error says so
450
+ * and points at the retry (deploys are idempotent).
451
+ */ async function runAspectSync(plan, output) {
452
+ try {
453
+ await applyAspectSync(plan);
454
+ } catch (err) {
455
+ throw new Error(`The config deployed, but syncing its aspect documents to media library ${plan.mediaLibraryId} failed: ${getErrorMessage(err)}\nRun \`sanity deploy\` again to retry the sync.`, {
456
+ cause: err
457
+ });
458
+ }
459
+ const deleted = plan.staleIds.length > 0 ? ` (deleted ${plan.staleIds.length} stale ${pluralize('definition', plan.staleIds.length)})` : '';
460
+ output.log(`Synced ${plan.documents.length} aspect ${pluralize('definition', plan.documents.length)} to media library ${plan.mediaLibraryId}${deleted}`);
461
+ }
346
462
  /**
347
463
  * Finds the application a real deploy targets, creating one when none is
348
464
  * configured. A dry run resolves and reports the target read-only instead.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {resolveAppEntry} from '@sanity/workbench-cli/build'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n const hasAppView = resolveAppEntry(cliConfig.app) !== undefined\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n hasAppView,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\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 const built = await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n // A federated build has already read its manifest; anything else verifies the directory.\n const mfManifest =\n built?.mfManifest ??\n (await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n }))\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n if (!mfManifest) throw new Error('The federated build produced no manifest.')\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n mfManifest,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = hasAppView\n ? getApplicationUrl({\n id: applicationId,\n organizationId,\n slug: workbench.slug,\n type: 'coreApp',\n })\n : getWorkbenchUrl(organizationId)\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.logDiagnostic(`Warning: Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","spinner","resolveAppEntry","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","hasAppView","undefined","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","built","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","mfManifest","manifest","installationId","configSummary","configAppType","appType","interfaces","deployApplicationConfig","payload","Error","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","logDiagnostic","tarball","cwd","pipe","error","clear","named"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {resolveAppEntry} from '@sanity/workbench-cli/build'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {runStep} from '../../util/checks.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n applyAspectSync,\n type AspectSyncPlan,\n planAspectSync,\n} from '../media/aspectSync/syncAspects.js'\nimport {checkBlueprintManaged} from './blueprintManaged.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n const hasAppView = resolveAppEntry(cliConfig.app) !== undefined\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n await checkBlueprintManaged(reporter, {kind: 'coreApp', projectRootDir: workDir})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n hasAppView,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\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 const built = await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n // A federated build has already read its manifest; anything else verifies the directory.\n const mfManifest =\n built?.mfManifest ??\n (await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n }))\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Plan the aspect-document sync in both modes, so the report — dry-run and\n // real — shows what the sync will write and, prominently, what it will\n // delete, before anything mutates. Gated on a resolved installation: when\n // that check failed, a real run already exited and a dry run has reported\n // the config as undeployable.\n let aspectSyncPlan: AspectSyncPlan | undefined\n // Gated on the `appType` discriminator, not the mere presence of a config:\n // `ConfigSchema` is a union built to grow, and a future config type must\n // not inherit the media-library aspect sync — and its deletions — by\n // default.\n if (configAppType === 'media-library' && organizationId && config && installationId) {\n // runStep so an unexpected throw (network, API) becomes a fail check:\n // a real run exits, a dry run records it and keeps reporting.\n const planned = await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Planning the aspect-document sync failed: ${getErrorMessage(err)}`,\n name: 'aspect sync plan',\n work: () =>\n planAspectSync({\n fields: config.fields,\n mediaLibraryId: flags['media-library-id'],\n organizationId,\n workDir,\n }),\n })\n if (planned && 'failure' in planned) {\n reporter.report({\n exitCode: planned.failure.exitCode,\n message: planned.failure.message,\n solution: planned.failure.solution,\n status: 'fail',\n })\n } else if (planned) {\n aspectSyncPlan = planned.plan\n reportAspectSyncPlan(reporter, aspectSyncPlan)\n }\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n ...(aspectSyncPlan\n ? {\n aspectSync: {\n deleteIds: aspectSyncPlan.staleIds,\n mediaLibraryId: aspectSyncPlan.mediaLibraryId,\n upsertIds: aspectSyncPlan.documents.map((document) => document._id),\n },\n }\n : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // Deleting stored definitions is the destructive part of a config deploy,\n // so an interactive run confirms it before anything mutates. Unattended\n // runs (--yes; forced in CI) proceed — the config is the source of truth\n // and the dry-run report lists the deletions.\n if (aspectSyncPlan && aspectSyncPlan.staleIds.length > 0 && !flags.yes) {\n const staleCount = aspectSyncPlan.staleIds.length\n const proceed = await confirm({\n default: false,\n message:\n `Delete ${staleCount} stored aspect ${pluralize('definition', staleCount)} with no ` +\n `matching config field (${aspectSyncPlan.staleIds.join(', ')})?`,\n })\n if (!proceed) {\n output.error('Deploy cancelled — the stored aspect definitions are unchanged.', {\n exit: exitCodes.USER_ABORT,\n })\n }\n }\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (aspectSyncPlan) {\n await runAspectSync(aspectSyncPlan, output)\n }\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n if (!mfManifest) throw new Error('The federated build produced no manifest.')\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n mfManifest,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = hasAppView\n ? getApplicationUrl({\n id: applicationId,\n organizationId,\n slug: workbench.slug,\n type: 'coreApp',\n })\n : getWorkbenchUrl(organizationId)\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Reports the planned aspect-document sync: the upserts as a pass, stripped\n * non-serializable values as information, and — prominently, as a warning —\n * the stored definitions the sync will delete because no config field matches\n * them. Deploy is a mirror: the config owns the library's aspect namespace.\n */\nexport function reportAspectSyncPlan(reporter: DeployCheckReporter, plan: AspectSyncPlan): void {\n const upserts = plan.documents.length\n reporter.report({\n message: `Will sync ${upserts} aspect ${pluralize('definition', upserts)} to media library ${plan.mediaLibraryId}`,\n status: 'pass',\n })\n\n const strippedFields = Object.entries(plan.strippedByField)\n if (strippedFields.length > 0) {\n // Expected for fields with custom inputs, validation callbacks, or\n // initial-value resolvers: the live config keeps those capabilities, only\n // the stored mirror (read by Studio plugin mode and the dashboard) omits\n // them. Reported so the capability gap is explicit, but not a warning.\n const details = strippedFields\n .map(([name, paths]) => `${name} (${paths.join(', ')})`)\n .join('; ')\n reporter.report({\n message: `Stored definitions omit non-serializable values: ${details}`,\n status: 'pass',\n })\n }\n\n if (plan.staleIds.length > 0) {\n reporter.report({\n message: `Will delete ${plan.staleIds.length} stored aspect ${pluralize('definition', plan.staleIds.length)} with no matching config field: ${plan.staleIds.join(', ')}`,\n solution:\n 'Definitions only — aspects.<name> values on assets stay put and resurface if a matching ' +\n 'field is added back. To keep a definition, declare a matching field in sanity.cli.ts ' +\n '(generate one with `sanity media pull-aspects`)',\n status: 'warn',\n })\n }\n}\n\n/**\n * Applies the planned sync after the config itself deployed. A failure here\n * leaves the config live but the stored mirror stale, so the error says so\n * and points at the retry (deploys are idempotent).\n */\nasync function runAspectSync(\n plan: AspectSyncPlan,\n output: DeployAppOptions['output'],\n): Promise<void> {\n try {\n await applyAspectSync(plan)\n } catch (err) {\n throw new Error(\n `The config deployed, but syncing its aspect documents to media library ${plan.mediaLibraryId} failed: ${getErrorMessage(err)}\\nRun \\`sanity deploy\\` again to retry the sync.`,\n {cause: err},\n )\n }\n const deleted =\n plan.staleIds.length > 0\n ? ` (deleted ${plan.staleIds.length} stale ${pluralize('definition', plan.staleIds.length)})`\n : ''\n output.log(\n `Synced ${plan.documents.length} aspect ${pluralize('definition', plan.documents.length)} to media library ${plan.mediaLibraryId}${deleted}`,\n )\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.logDiagnostic(`Warning: Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","confirm","spinner","resolveAppEntry","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","runStep","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","pluralize","buildApp","applyAspectSync","planAspectSync","checkBlueprintManaged","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","hasAppView","undefined","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","kind","projectRootDir","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","built","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","mfManifest","manifest","installationId","configSummary","configAppType","appType","aspectSyncPlan","planned","debug","formatError","work","mediaLibraryId","failure","plan","reportAspectSyncPlan","interfaces","deployApplicationConfig","payload","aspectSync","deleteIds","staleIds","upsertIds","documents","map","document","_id","yes","staleCount","proceed","default","join","error","exit","USER_ABORT","runAspectSync","Error","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","upserts","strippedFields","Object","entries","strippedByField","details","paths","cause","deleted","log","unattended","titleUpdate","visibilityChanged","dashboardStatus","from","to","spin","start","updated","body","succeed","fail","logDiagnostic","tarball","cwd","pipe","clear","named"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployRunner.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {getErrorMessage, JsonOutputError} from '@sanity/cli-core/errors'\nimport {type WorkbenchDeployPayload} from '@sanity/workbench-cli/deploy'\n\nimport {createCollectingReporter, createFailFastReporter} from '../../util/checks.js'\nimport {toStderrOutput} from '../../util/toStderrOutput.js'\nimport {type DeployCheck, type DeployCheckReporter, type DeployTarget} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type DeploymentFile,\n type DeploymentPlan,\n deploymentPlanToJson,\n isDeployable,\n renderDeploymentPlan,\n} from './deploymentPlan.js'\nimport {type DeployAppOptions} from './types.js'\n\nexport interface DeployResult {\n application: object | null\n payload: DeployPayload\n\n action?: DeployTarget['action']\n /** Resolved server-side, so it stays out of the local payload. */\n installationId?: string\n url?: string | null\n}\n\n/** Collected locally, so a dry run reports it too. */\nexport interface DeployPayload extends Partial<WorkbenchDeployPayload> {\n /** The configured `deployment.appId`; `null` when the deploy would mint one. */\n appId: string | null\n isAutoUpdating: boolean\n type: 'coreApp' | 'studio'\n version: string | null\n\n organizationId?: string\n projectId?: string\n}\n\n/**\n * The parts of a deploy that differ between core apps and studios. The shared\n * sequence — mode selection, error handling, the dry-run plan, `--json` — lives\n * in `runDeploy`.\n */\nexport interface DeploySpec {\n /** Files a real deploy would upload, listed only for the dry-run plan. */\n listFiles: (options: DeployAppOptions) => Promise<DeploymentFile[]>\n /** The step sequence; every step reports through `reporter`. */\n run: (options: DeployAppOptions, reporter: DeployCheckReporter) => Promise<DeployResult | void>\n type: 'coreApp' | 'studio'\n}\n\n/**\n * Runs a deploy in the mode the flags select: a real deploy fails fast and\n * mutates, `--dry-run` drives the same `run` sequence read-only and renders a\n * plan, and `--json` emits the same information as machine-readable JSON.\n */\nexport async function runDeploy(options: DeployAppOptions, spec: DeploySpec): Promise<void> {\n const {output} = options\n const json = !!options.flags.json\n const emitJson = (payload: unknown) => output.logJson(payload)\n let failurePayload: unknown\n\n // The JSON payload owns stdout, so the run's progress logs go to stderr; only\n // the final JSON.stringify writes to stdout.\n const runOptions = json ? {...options, output: toStderrOutput(output)} : options\n\n try {\n if (options.flags['dry-run']) {\n const plan = await collectPlan(runOptions, spec)\n if (json) {\n const payload = deploymentPlanToJson(plan)\n if (isDeployable(plan)) emitJson(payload)\n else failurePayload = payload\n } else renderDeploymentPlan(plan, output)\n exitIfBlocked(plan, output)\n return\n }\n\n const result = await spec.run(runOptions, createFailFastReporter(runOptions.output))\n if (json && result) emitJson({deployed: true, reason: null, ...result})\n } catch (error) {\n const failure = normalizeFailure(error, spec.type)\n // Preserve the blocked plan or the existing deployment failure envelope.\n if (json && !options.flags['dry-run']) {\n failurePayload = {\n application: null,\n deployed: false,\n error: {message: failure.message},\n payload: null,\n reason: failure.message,\n }\n }\n if (json && failurePayload !== undefined) {\n throw new JsonOutputError(failure.message, failurePayload, failure.exit)\n }\n output.error(failure.message, {exit: failure.exit})\n }\n}\n\n/** Runs the step sequence read-only and gathers the plan a dry run reports. */\nasync function collectPlan(options: DeployAppOptions, spec: DeploySpec): Promise<DeploymentPlan> {\n const reporter = createCollectingReporter<DeployCheck>()\n const result = await spec.run(options, reporter)\n const plan: DeploymentPlan = {\n checks: reporter.results,\n files: [],\n payload: result?.payload ?? null,\n target:\n reporter.results.find((check) => check.target && check.status !== 'fail')?.target ?? null,\n type: spec.type,\n }\n // A blocked deploy uploads nothing, so only enumerate files for a deployable plan.\n if (isDeployable(plan)) plan.files = await spec.listFiles(options)\n return plan\n}\n\n/** Exits like a real (fail-fast) deploy would, on the first failing check's exit code. */\nfunction exitIfBlocked(plan: DeploymentPlan, output: Output): void {\n if (isDeployable(plan)) return\n const failed = plan.checks.find((check) => check.status === 'fail')\n output.error('Deploy blocked by failing checks.', {exit: failed?.exitCode ?? 1})\n}\n\n/** The one failure diagnosis both the stderr message and the `--json` envelope read. */\nfunction normalizeFailure(\n error: unknown,\n type: 'coreApp' | 'studio',\n): {exit: number; message: string} {\n // Ctrl+C on an interactive prompt isn't a real failure\n if (error instanceof Error && error.name === 'ExitPromptError') {\n return {exit: exitCodes.RUNTIME_ERROR, message: 'Deployment cancelled by user'}\n }\n // A failed check already carries its own message and exit code\n if (error instanceof CLIError) {\n return {exit: error.oclif?.exit ?? 1, message: error.message}\n }\n deployDebug(`Error deploying ${type === 'coreApp' ? 'application' : 'studio'}`, error)\n return {\n exit: exitCodes.RUNTIME_ERROR,\n message: `Error deploying ${type === 'coreApp' ? 'application' : 'studio'}: ${getErrorMessage(error)}`,\n }\n}\n"],"names":["CLIError","exitCodes","getErrorMessage","JsonOutputError","createCollectingReporter","createFailFastReporter","toStderrOutput","deployDebug","deploymentPlanToJson","isDeployable","renderDeploymentPlan","runDeploy","options","spec","output","json","flags","emitJson","payload","logJson","failurePayload","runOptions","plan","collectPlan","exitIfBlocked","result","run","deployed","reason","error","failure","normalizeFailure","type","application","message","undefined","exit","reporter","checks","results","files","target","find","check","status","listFiles","failed","exitCode","Error","name","RUNTIME_ERROR","oclif"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployRunner.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {getErrorMessage, JsonOutputError} from '@sanity/cli-core/errors'\nimport {type WorkbenchDeployPayload} from '@sanity/workbench-cli/deploy'\n\nimport {createCollectingReporter, createFailFastReporter} from '../../util/checks.js'\nimport {toStderrOutput} from '../../util/toStderrOutput.js'\nimport {type DeployCheck, type DeployCheckReporter, type DeployTarget} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type DeploymentFile,\n type DeploymentPlan,\n deploymentPlanToJson,\n isDeployable,\n renderDeploymentPlan,\n} from './deploymentPlan.js'\nimport {type DeployAppOptions} from './types.js'\n\nexport interface DeployResult {\n application: object | null\n payload: DeployPayload\n\n action?: DeployTarget['action']\n /** Resolved server-side, so it stays out of the local payload. */\n installationId?: string\n url?: string | null\n}\n\n/** Collected locally, so a dry run reports it too. */\nexport interface DeployPayload extends Partial<WorkbenchDeployPayload> {\n /** The configured `deployment.appId`; `null` when the deploy would mint one. */\n appId: string | null\n isAutoUpdating: boolean\n type: 'coreApp' | 'studio'\n version: string | null\n\n /**\n * The aspect-document sync a media-library config deploy will run: every\n * config field is upserted, stored definitions without a matching config\n * field are deleted (the config mirrors into the library). Collected during\n * planning, so a `--dry-run --json` consumer sees the deletions too.\n */\n aspectSync?: {\n deleteIds: string[]\n mediaLibraryId: string\n upsertIds: string[]\n }\n organizationId?: string\n projectId?: string\n}\n\n/**\n * The parts of a deploy that differ between core apps and studios. The shared\n * sequence — mode selection, error handling, the dry-run plan, `--json` — lives\n * in `runDeploy`.\n */\nexport interface DeploySpec {\n /** Files a real deploy would upload, listed only for the dry-run plan. */\n listFiles: (options: DeployAppOptions) => Promise<DeploymentFile[]>\n /** The step sequence; every step reports through `reporter`. */\n run: (options: DeployAppOptions, reporter: DeployCheckReporter) => Promise<DeployResult | void>\n type: 'coreApp' | 'studio'\n}\n\n/**\n * Runs a deploy in the mode the flags select: a real deploy fails fast and\n * mutates, `--dry-run` drives the same `run` sequence read-only and renders a\n * plan, and `--json` emits the same information as machine-readable JSON.\n */\nexport async function runDeploy(options: DeployAppOptions, spec: DeploySpec): Promise<void> {\n const {output} = options\n const json = !!options.flags.json\n const emitJson = (payload: unknown) => output.logJson(payload)\n let failurePayload: unknown\n\n // The JSON payload owns stdout, so the run's progress logs go to stderr; only\n // the final JSON.stringify writes to stdout.\n const runOptions = json ? {...options, output: toStderrOutput(output)} : options\n\n try {\n if (options.flags['dry-run']) {\n const plan = await collectPlan(runOptions, spec)\n if (json) {\n const payload = deploymentPlanToJson(plan)\n if (isDeployable(plan)) emitJson(payload)\n else failurePayload = payload\n } else renderDeploymentPlan(plan, output)\n exitIfBlocked(plan, output)\n return\n }\n\n const result = await spec.run(runOptions, createFailFastReporter(runOptions.output))\n if (json && result) emitJson({deployed: true, reason: null, ...result})\n } catch (error) {\n const failure = normalizeFailure(error, spec.type)\n // Preserve the blocked plan or the existing deployment failure envelope.\n if (json && !options.flags['dry-run']) {\n failurePayload = {\n application: null,\n deployed: false,\n error: {message: failure.message},\n payload: null,\n reason: failure.message,\n }\n }\n if (json && failurePayload !== undefined) {\n throw new JsonOutputError(failure.message, failurePayload, failure.exit)\n }\n output.error(failure.message, {exit: failure.exit})\n }\n}\n\n/** Runs the step sequence read-only and gathers the plan a dry run reports. */\nasync function collectPlan(options: DeployAppOptions, spec: DeploySpec): Promise<DeploymentPlan> {\n const reporter = createCollectingReporter<DeployCheck>()\n const result = await spec.run(options, reporter)\n const plan: DeploymentPlan = {\n checks: reporter.results,\n files: [],\n payload: result?.payload ?? null,\n target:\n reporter.results.find((check) => check.target && check.status !== 'fail')?.target ?? null,\n type: spec.type,\n }\n // A blocked deploy uploads nothing, so only enumerate files for a deployable plan.\n if (isDeployable(plan)) plan.files = await spec.listFiles(options)\n return plan\n}\n\n/** Exits like a real (fail-fast) deploy would, on the first failing check's exit code. */\nfunction exitIfBlocked(plan: DeploymentPlan, output: Output): void {\n if (isDeployable(plan)) return\n const failed = plan.checks.find((check) => check.status === 'fail')\n output.error('Deploy blocked by failing checks.', {exit: failed?.exitCode ?? 1})\n}\n\n/** The one failure diagnosis both the stderr message and the `--json` envelope read. */\nfunction normalizeFailure(\n error: unknown,\n type: 'coreApp' | 'studio',\n): {exit: number; message: string} {\n // Ctrl+C on an interactive prompt isn't a real failure\n if (error instanceof Error && error.name === 'ExitPromptError') {\n return {exit: exitCodes.RUNTIME_ERROR, message: 'Deployment cancelled by user'}\n }\n // A failed check already carries its own message and exit code\n if (error instanceof CLIError) {\n return {exit: error.oclif?.exit ?? 1, message: error.message}\n }\n deployDebug(`Error deploying ${type === 'coreApp' ? 'application' : 'studio'}`, error)\n return {\n exit: exitCodes.RUNTIME_ERROR,\n message: `Error deploying ${type === 'coreApp' ? 'application' : 'studio'}: ${getErrorMessage(error)}`,\n }\n}\n"],"names":["CLIError","exitCodes","getErrorMessage","JsonOutputError","createCollectingReporter","createFailFastReporter","toStderrOutput","deployDebug","deploymentPlanToJson","isDeployable","renderDeploymentPlan","runDeploy","options","spec","output","json","flags","emitJson","payload","logJson","failurePayload","runOptions","plan","collectPlan","exitIfBlocked","result","run","deployed","reason","error","failure","normalizeFailure","type","application","message","undefined","exit","reporter","checks","results","files","target","find","check","status","listFiles","failed","exitCode","Error","name","RUNTIME_ERROR","oclif"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
- import { basename, dirname, join, relative } 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
- import { findBlueprintFile, readBlueprint } from '@sanity/blueprints/resolve';
5
4
  import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
6
5
  import { readIconFromPath } from '@sanity/cli-build/_internal/manifest';
7
6
  import { exitCodes } from '@sanity/cli-core';
@@ -12,6 +11,7 @@ import { createDeployment } from '../../services/userApplications.js';
12
11
  import { getAppId } from '../../util/appId.js';
13
12
  import { NO_ORGANIZATION_ID, NO_PROJECT_ID } from '../../util/errorMessages.js';
14
13
  import { buildStudio } from '../build/buildStudio.js';
14
+ import { checkBlueprintManaged } from './blueprintManaged.js';
15
15
  import { createStudioUserApplication } from './createUserApplication.js';
16
16
  import { checkAutoUpdates, checkBuild, checkExternalUrl, checkPackageVersion, checkStudioTarget, verifyOutputDir } from './deployChecks.js';
17
17
  import { deployDebug } from './deployDebug.js';
@@ -57,13 +57,10 @@ export function deployStudio(options) {
57
57
  solution: 'Add `api.projectId` to sanity.cli.ts',
58
58
  status: 'fail'
59
59
  });
60
- if (await isBlueprintStudio(options.projectRoot.directory)) {
61
- reporter.report({
62
- message: 'Using the `deploy` command for a studio that is referenced by a blueprint is not allowed',
63
- solution: 'Deploy the studio using the `blueprints deploy` command',
64
- status: 'fail'
65
- });
66
- }
60
+ await checkBlueprintManaged(reporter, {
61
+ kind: 'studio',
62
+ projectRootDir: workDir
63
+ });
67
64
  // Workbench studios deploy to Brett (which needs the org); plain studios
68
65
  // resolve/create on user-applications, unchanged.
69
66
  let application = null;
@@ -442,27 +439,5 @@ function studioBuildSkipReason({ build, isLegacyExternal }) {
442
439
  if (!build) return 'Build skipped (--no-build) — validating existing output directory';
443
440
  return;
444
441
  }
445
- /**
446
- * Determine if the blueprint being deployed is referenced by a blueprint.
447
- * @param projectRootDir - The root directory of the studio
448
- */ async function isBlueprintStudio(projectRootDir) {
449
- try {
450
- const blueprintFile = findBlueprintFile(projectRootDir);
451
- if (!blueprintFile) return false;
452
- const localBlueprint = await readBlueprint({
453
- path: blueprintFile
454
- });
455
- const blueprintReferencesStudio = localBlueprint.resources.some((r)=>{
456
- if (r.type === 'sanity.studio' && 'root' in r && typeof r.root === 'string') {
457
- return relative(join(dirname(blueprintFile), r.root), projectRootDir) === '';
458
- }
459
- return false;
460
- });
461
- return blueprintReferencesStudio;
462
- } catch {
463
- return false // fail open
464
- ;
465
- }
466
- }
467
442
 
468
443
  //# sourceMappingURL=deployStudio.js.map