@sanity/cli 8.25.0 → 8.27.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 (127) hide show
  1. package/README.md +3 -2
  2. package/dist/actions/build/shouldAutoUpdate.js +1 -26
  3. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  4. package/dist/actions/context/mcpEndpoint.js +165 -0
  5. package/dist/actions/context/mcpEndpoint.js.map +1 -0
  6. package/dist/actions/context/resolveOrganizationId.js +8 -1
  7. package/dist/actions/context/resolveOrganizationId.js.map +1 -1
  8. package/dist/actions/deploy/deployApp.js +10 -3
  9. package/dist/actions/deploy/deployApp.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +11 -4
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/init/initAction.js +3 -3
  13. package/dist/actions/init/initAction.js.map +1 -1
  14. package/dist/actions/init/plan/verifyCoupon.js +0 -1
  15. package/dist/actions/init/plan/verifyCoupon.js.map +1 -1
  16. package/dist/actions/init/scaffoldTemplate.js +1 -1
  17. package/dist/actions/init/scaffoldTemplate.js.map +1 -1
  18. package/dist/commands/api.js +10 -0
  19. package/dist/commands/api.js.map +1 -1
  20. package/dist/commands/backups/download.js +6 -0
  21. package/dist/commands/backups/download.js.map +1 -1
  22. package/dist/commands/context/create.js +8 -22
  23. package/dist/commands/context/create.js.map +1 -1
  24. package/dist/commands/context/delete.js +8 -1
  25. package/dist/commands/context/delete.js.map +1 -1
  26. package/dist/commands/context/issues/list.js +0 -5
  27. package/dist/commands/context/issues/list.js.map +1 -1
  28. package/dist/commands/context/list.js +6 -14
  29. package/dist/commands/context/list.js.map +1 -1
  30. package/dist/commands/context/mcp/create.js +152 -0
  31. package/dist/commands/context/mcp/create.js.map +1 -0
  32. package/dist/commands/context/mcp/delete.js +82 -0
  33. package/dist/commands/context/mcp/delete.js.map +1 -0
  34. package/dist/commands/context/mcp/get.js +42 -0
  35. package/dist/commands/context/mcp/get.js.map +1 -0
  36. package/dist/commands/context/mcp/list.js +87 -0
  37. package/dist/commands/context/mcp/list.js.map +1 -0
  38. package/dist/commands/context/mcp/status.js +98 -0
  39. package/dist/commands/context/mcp/status.js.map +1 -0
  40. package/dist/commands/context/mcp/update.js +225 -0
  41. package/dist/commands/context/mcp/update.js.map +1 -0
  42. package/dist/commands/context/query.js +6 -14
  43. package/dist/commands/context/query.js.map +1 -1
  44. package/dist/commands/context/update.js +12 -1
  45. package/dist/commands/context/update.js.map +1 -1
  46. package/dist/commands/datasets/create.js +6 -0
  47. package/dist/commands/datasets/create.js.map +1 -1
  48. package/dist/commands/datasets/embeddings/enable.js +6 -0
  49. package/dist/commands/datasets/embeddings/enable.js.map +1 -1
  50. package/dist/commands/datasets/import.js +6 -0
  51. package/dist/commands/datasets/import.js.map +1 -1
  52. package/dist/commands/deploy.js +7 -0
  53. package/dist/commands/deploy.js.map +1 -1
  54. package/dist/commands/documents/validate.js +6 -0
  55. package/dist/commands/documents/validate.js.map +1 -1
  56. package/dist/commands/exec.js +4 -2
  57. package/dist/commands/exec.js.map +1 -1
  58. package/dist/commands/init.js +13 -0
  59. package/dist/commands/init.js.map +1 -1
  60. package/dist/commands/manifest/extract.js +6 -0
  61. package/dist/commands/manifest/extract.js.map +1 -1
  62. package/dist/commands/media/create-aspect.js +7 -0
  63. package/dist/commands/media/create-aspect.js.map +1 -1
  64. package/dist/commands/migrations/run.js +6 -0
  65. package/dist/commands/migrations/run.js.map +1 -1
  66. package/dist/commands/organizations/create.js +6 -0
  67. package/dist/commands/organizations/create.js.map +1 -1
  68. package/dist/commands/organizations/update.js +6 -0
  69. package/dist/commands/organizations/update.js.map +1 -1
  70. package/dist/commands/schemas/delete.js +6 -0
  71. package/dist/commands/schemas/delete.js.map +1 -1
  72. package/dist/commands/schemas/deploy.js +6 -0
  73. package/dist/commands/schemas/deploy.js.map +1 -1
  74. package/dist/commands/schemas/extract.js +28 -3
  75. package/dist/commands/schemas/extract.js.map +1 -1
  76. package/dist/commands/schemas/list.js +6 -0
  77. package/dist/commands/schemas/list.js.map +1 -1
  78. package/dist/commands/schemas/validate.js +6 -0
  79. package/dist/commands/schemas/validate.js.map +1 -1
  80. package/dist/commands/tokens/rotate.js +6 -0
  81. package/dist/commands/tokens/rotate.js.map +1 -1
  82. package/dist/commands/typegen/generate.js +25 -1
  83. package/dist/commands/typegen/generate.js.map +1 -1
  84. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
  85. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  86. package/dist/generated/apiRoutes.js +22 -0
  87. package/dist/generated/apiRoutes.js.map +1 -1
  88. package/dist/hooks/prerun/setupTelemetry.js +2 -3
  89. package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
  90. package/dist/prompts/promptForText.js +12 -0
  91. package/dist/prompts/promptForText.js.map +1 -0
  92. package/dist/services/context.js +174 -1
  93. package/dist/services/context.js.map +1 -1
  94. package/dist/services/telemetry.js +4 -2
  95. package/dist/services/telemetry.js.map +1 -1
  96. package/dist/telemetry/cli.telemetry.js +1 -1
  97. package/dist/telemetry/cli.telemetry.js.map +1 -1
  98. package/dist/telemetry/init.telemetry.js +1 -1
  99. package/dist/telemetry/init.telemetry.js.map +1 -1
  100. package/dist/telemetry/typegen.telemetry.js +12 -0
  101. package/dist/telemetry/typegen.telemetry.js.map +1 -0
  102. package/dist/util/parseArguments.js +12 -40
  103. package/dist/util/parseArguments.js.map +1 -1
  104. package/dist/util/sharedFlags.js.map +1 -1
  105. package/dist/util/telemetry/cliCommandIdentity.js +222 -0
  106. package/dist/util/telemetry/cliCommandIdentity.js.map +1 -0
  107. package/dist/util/telemetry/cliTelemetryFlags.js +186 -0
  108. package/dist/util/telemetry/cliTelemetryFlags.js.map +1 -0
  109. package/dist/util/telemetry/commandTelemetry.js +56 -11
  110. package/dist/util/telemetry/commandTelemetry.js.map +1 -1
  111. package/dist/util/telemetry/createTelemetryStore.js +13 -5
  112. package/dist/util/telemetry/createTelemetryStore.js.map +1 -1
  113. package/dist/util/telemetry/createTraceId.js +3 -3
  114. package/dist/util/telemetry/createTraceId.js.map +1 -1
  115. package/dist/util/telemetry/flushTelemetryFiles.js +14 -4
  116. package/dist/util/telemetry/flushTelemetryFiles.js.map +1 -1
  117. package/dist/util/telemetry/logger.js +1 -1
  118. package/dist/util/telemetry/logger.js.map +1 -1
  119. package/dist/util/telemetry/readNDJSON.js +1 -1
  120. package/dist/util/telemetry/readNDJSON.js.map +1 -1
  121. package/dist/util/telemetry/sanitizeTelemetryEvent.js +304 -0
  122. package/dist/util/telemetry/sanitizeTelemetryEvent.js.map +1 -0
  123. package/dist/util/telemetry/trace.js +4 -7
  124. package/dist/util/telemetry/trace.js.map +1 -1
  125. package/oclif.config.js +1 -1
  126. package/oclif.manifest.json +2380 -1526
  127. package/package.json +8 -11
package/README.md CHANGED
@@ -4234,10 +4234,11 @@ Extract a JSON representation of a Sanity schema within a Studio context.
4234
4234
 
4235
4235
  ```
4236
4236
  USAGE
4237
- $ sanity schemas extract [--enforce-required-fields] [--force] [--format <format>] [--path <value>] [--watch]
4238
- [--watch-patterns <glob>...] [--workspace <name>]
4237
+ $ sanity schemas extract [--config-path <path>] [--enforce-required-fields] [--force] [--format <format>] [--path
4238
+ <value>] [--watch] [--watch-patterns <glob>...] [--workspace <name>]
4239
4239
 
4240
4240
  FLAGS
4241
+ --config-path=<path> Path to the Sanity Studio config file
4241
4242
  --enforce-required-fields Makes the schema generated treat fields marked as required as non-optional
4242
4243
  --force Overwrite an existing schema file
4243
4244
  --format=<format> [default: groq-type-nodes] Output format (currently only groq-type-nodes)
@@ -1,31 +1,11 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { exitCodes } from '@sanity/cli-core';
3
- import { isWorkbenchApp } from '@sanity/workbench-cli';
4
3
  /**
5
4
  * Owns the auto-update rules and returns plain facts, so each surface (build,
6
5
  * dev, deploy warnings, dry-run checks) decides its own presentation.
7
6
  *
8
7
  * @internal
9
- */ export function resolveAutoUpdates(sources) {
10
- const settings = resolveConfiguredAutoUpdates(sources);
11
- // A workbench app takes `sanity` from the shell's shared runtime, so it has no
12
- // version of its own to pin.
13
- // TODO(SDK-1045): confirm the long-term story with the studio team.
14
- if (settings.enabled && isWorkbenchApp(sources.cliConfig?.app)) {
15
- // A config conflict still fails — it's a problem with the config itself.
16
- return settings.issue?.type === 'conflicting-config' ? {
17
- enabled: false,
18
- issue: settings.issue
19
- } : {
20
- enabled: false,
21
- issue: {
22
- type: 'unsupported'
23
- }
24
- };
25
- }
26
- return settings;
27
- }
28
- function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
8
+ */ export function resolveAutoUpdates({ cliConfig, flags }) {
29
9
  // Flags always take precedence over config
30
10
  if ('auto-updates' in flags) {
31
11
  const enabled = Boolean(flags['auto-updates']);
@@ -80,10 +60,6 @@ function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
80
60
  {
81
61
  return `The ${issue.flag} flag is deprecated for deploy and build commands. Set the autoUpdates option in the deployment section of sanity.cli.ts or sanity.cli.js instead.`;
82
62
  }
83
- case 'unsupported':
84
- {
85
- return "Auto-updates aren't supported yet — using the installed package versions";
86
- }
87
63
  }
88
64
  }
89
65
  /**
@@ -123,7 +99,6 @@ function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
123
99
  break;
124
100
  }
125
101
  case 'deprecated-flag':
126
- case 'unsupported':
127
102
  {
128
103
  output.warn(getAutoUpdateIssueMessage(issue));
129
104
  break;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, exitCodes, type Output} from '@sanity/cli-core'\nimport {isWorkbenchApp} from '@sanity/workbench-cli'\n\nimport {type DeployFlags} from '../deploy/types.js'\nimport {type DevFlags} from '../dev/types.js'\nimport {type BuildFlags} from './types.js'\n\ninterface AutoUpdateSources {\n cliConfig: CliConfig\n flags: BuildFlags | DeployFlags | DevFlags\n}\n\n/**\n * The single auto-update configuration problem to surface, if any.\n * Flag usage takes precedence over config problems: when the deprecated flag\n * is passed, config is not consulted, so config issues are not reported.\n */\ntype AutoUpdateIssue =\n | {flag: '--auto-updates' | '--no-auto-updates'; type: 'deprecated-flag'}\n | {type: 'conflicting-config'}\n | {type: 'deprecated-config'}\n | {type: 'unsupported'}\n\nexport interface AutoUpdateSettings {\n enabled: boolean\n issue: AutoUpdateIssue | null\n}\n\n/**\n * Owns the auto-update rules and returns plain facts, so each surface (build,\n * dev, deploy warnings, dry-run checks) decides its own presentation.\n *\n * @internal\n */\nexport function resolveAutoUpdates(sources: AutoUpdateSources): AutoUpdateSettings {\n const settings = resolveConfiguredAutoUpdates(sources)\n\n // A workbench app takes `sanity` from the shell's shared runtime, so it has no\n // version of its own to pin.\n // TODO(SDK-1045): confirm the long-term story with the studio team.\n if (settings.enabled && isWorkbenchApp(sources.cliConfig?.app)) {\n // A config conflict still fails — it's a problem with the config itself.\n return settings.issue?.type === 'conflicting-config'\n ? {enabled: false, issue: settings.issue}\n : {enabled: false, issue: {type: 'unsupported'}}\n }\n\n return settings\n}\n\nfunction resolveConfiguredAutoUpdates({cliConfig, flags}: AutoUpdateSources): AutoUpdateSettings {\n // Flags always take precedence over config\n if ('auto-updates' in flags) {\n const enabled = Boolean(flags['auto-updates'])\n return {\n enabled,\n issue: {flag: enabled ? '--auto-updates' : '--no-auto-updates', type: 'deprecated-flag'},\n }\n }\n\n const hasOldConfig = cliConfig && 'autoUpdates' in cliConfig\n\n const hasNewConfig =\n cliConfig &&\n 'deployment' in cliConfig &&\n cliConfig.deployment &&\n 'autoUpdates' in cliConfig.deployment\n\n if (hasNewConfig) {\n return {\n enabled: Boolean(cliConfig?.deployment?.autoUpdates),\n issue: hasOldConfig ? {type: 'conflicting-config'} : null,\n }\n }\n\n if (hasOldConfig) {\n return {enabled: Boolean(cliConfig?.autoUpdates), issue: {type: 'deprecated-config'}}\n }\n\n return {enabled: false, issue: null}\n}\n\n/**\n * The user-facing message for an auto-update configuration problem.\n * Shared by every surface that reports the issue (deploy warnings, dry-run\n * checks) so the wording has one home.\n *\n * @internal\n */\nexport function getAutoUpdateIssueMessage(issue: AutoUpdateIssue): string {\n switch (issue.type) {\n case 'conflicting-config': {\n return 'Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.'\n }\n case 'deprecated-config': {\n return 'The autoUpdates config has moved to deployment.autoUpdates.'\n }\n case 'deprecated-flag': {\n return `The ${issue.flag} flag is deprecated for deploy and build commands. Set the autoUpdates option in the deployment section of sanity.cli.ts or sanity.cli.js instead.`\n }\n case 'unsupported': {\n return \"Auto-updates aren't supported yet — using the installed package versions\"\n }\n }\n}\n\n/**\n * The styled before/after edit that migrates the deprecated top-level\n * `autoUpdates` to `deployment.autoUpdates`. Lives here so every surface that\n * reports the deprecated config (deploy warnings, dry-run checks) shows the\n * same migration hint.\n *\n * @internal\n */\nexport function getAutoUpdateMigrationHint(currentValue: unknown): string {\n return `Please update sanity.cli.ts or sanity.cli.js and make the following change:\n ${styleText('red', `- autoUpdates: ${currentValue},`)}\n ${styleText('green', `+ deployment: {autoUpdates: ${currentValue}}`)}\n`\n}\n\n/**\n * Resolves the auto-update setting and prints any configuration problem.\n * @remarks Throws an error if both the old and new auto update config are used; throws a warning if the old config is used, or if the auto updates flags are used.\n * @internal\n */\nexport function shouldAutoUpdate({\n cliConfig,\n flags,\n output,\n}: AutoUpdateSources & {output: Output}): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n switch (issue?.type) {\n case 'conflicting-config': {\n output.error(getAutoUpdateIssueMessage(issue), {exit: exitCodes.RUNTIME_ERROR})\n break\n }\n case 'deprecated-config': {\n output.warn(getAutoUpdateIssueMessage(issue))\n output.warn(getAutoUpdateMigrationHint(cliConfig.autoUpdates))\n break\n }\n case 'deprecated-flag':\n case 'unsupported': {\n output.warn(getAutoUpdateIssueMessage(issue))\n break\n }\n default: {\n break\n }\n }\n\n return enabled\n}\n"],"names":["styleText","exitCodes","isWorkbenchApp","resolveAutoUpdates","sources","settings","resolveConfiguredAutoUpdates","enabled","cliConfig","app","issue","type","flags","Boolean","flag","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","RUNTIME_ERROR","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAwBC,SAAS,QAAoB,mBAAkB;AACvE,SAAQC,cAAc,QAAO,wBAAuB;AA2BpD;;;;;CAKC,GACD,OAAO,SAASC,mBAAmBC,OAA0B;IAC3D,MAAMC,WAAWC,6BAA6BF;IAE9C,+EAA+E;IAC/E,6BAA6B;IAC7B,oEAAoE;IACpE,IAAIC,SAASE,OAAO,IAAIL,eAAeE,QAAQI,SAAS,EAAEC,MAAM;QAC9D,yEAAyE;QACzE,OAAOJ,SAASK,KAAK,EAAEC,SAAS,uBAC5B;YAACJ,SAAS;YAAOG,OAAOL,SAASK,KAAK;QAAA,IACtC;YAACH,SAAS;YAAOG,OAAO;gBAACC,MAAM;YAAa;QAAC;IACnD;IAEA,OAAON;AACT;AAEA,SAASC,6BAA6B,EAACE,SAAS,EAAEI,KAAK,EAAoB;IACzE,2CAA2C;IAC3C,IAAI,kBAAkBA,OAAO;QAC3B,MAAML,UAAUM,QAAQD,KAAK,CAAC,eAAe;QAC7C,OAAO;YACLL;YACAG,OAAO;gBAACI,MAAMP,UAAU,mBAAmB;gBAAqBI,MAAM;YAAiB;QACzF;IACF;IAEA,MAAMI,eAAeP,aAAa,iBAAiBA;IAEnD,MAAMQ,eACJR,aACA,gBAAgBA,aAChBA,UAAUS,UAAU,IACpB,iBAAiBT,UAAUS,UAAU;IAEvC,IAAID,cAAc;QAChB,OAAO;YACLT,SAASM,QAAQL,WAAWS,YAAYC;YACxCR,OAAOK,eAAe;gBAACJ,MAAM;YAAoB,IAAI;QACvD;IACF;IAEA,IAAII,cAAc;QAChB,OAAO;YAACR,SAASM,QAAQL,WAAWU;YAAcR,OAAO;gBAACC,MAAM;YAAmB;QAAC;IACtF;IAEA,OAAO;QAACJ,SAAS;QAAOG,OAAO;IAAI;AACrC;AAEA;;;;;;CAMC,GACD,OAAO,SAASS,0BAA0BT,KAAsB;IAC9D,OAAQA,MAAMC,IAAI;QAChB,KAAK;YAAsB;gBACzB,OAAO;YACT;QACA,KAAK;YAAqB;gBACxB,OAAO;YACT;QACA,KAAK;YAAmB;gBACtB,OAAO,CAAC,IAAI,EAAED,MAAMI,IAAI,CAAC,kJAAkJ,CAAC;YAC9K;QACA,KAAK;YAAe;gBAClB,OAAO;YACT;IACF;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASM,2BAA2BC,YAAqB;IAC9D,OAAO,CAAC;EACR,EAAErB,UAAU,OAAO,CAAC,gBAAgB,EAAEqB,aAAa,CAAC,CAAC,EAAE;EACvD,EAAErB,UAAU,SAAS,CAAC,6BAA6B,EAAEqB,aAAa,CAAC,CAAC,EAAE;AACxE,CAAC;AACD;AAEA;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAC/Bd,SAAS,EACTI,KAAK,EACLW,MAAM,EAC+B;IACrC,MAAM,EAAChB,OAAO,EAAEG,KAAK,EAAC,GAAGP,mBAAmB;QAACK;QAAWI;IAAK;IAE7D,OAAQF,OAAOC;QACb,KAAK;YAAsB;gBACzBY,OAAOC,KAAK,CAACL,0BAA0BT,QAAQ;oBAACe,MAAMxB,UAAUyB,aAAa;gBAAA;gBAC7E;YACF;QACA,KAAK;YAAqB;gBACxBH,OAAOI,IAAI,CAACR,0BAA0BT;gBACtCa,OAAOI,IAAI,CAACP,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;QACL,KAAK;YAAe;gBAClBK,OAAOI,IAAI,CAACR,0BAA0BT;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOH;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, exitCodes, type Output} from '@sanity/cli-core'\n\nimport {type DeployFlags} from '../deploy/types.js'\nimport {type DevFlags} from '../dev/types.js'\nimport {type BuildFlags} from './types.js'\n\ninterface AutoUpdateSources {\n cliConfig: CliConfig\n flags: BuildFlags | DeployFlags | DevFlags\n}\n\n/**\n * The single auto-update configuration problem to surface, if any.\n * Flag usage takes precedence over config problems: when the deprecated flag\n * is passed, config is not consulted, so config issues are not reported.\n */\ntype AutoUpdateIssue =\n | {flag: '--auto-updates' | '--no-auto-updates'; type: 'deprecated-flag'}\n | {type: 'conflicting-config'}\n | {type: 'deprecated-config'}\n\nexport interface AutoUpdateSettings {\n enabled: boolean\n issue: AutoUpdateIssue | null\n}\n\n/**\n * Owns the auto-update rules and returns plain facts, so each surface (build,\n * dev, deploy warnings, dry-run checks) decides its own presentation.\n *\n * @internal\n */\nexport function resolveAutoUpdates({cliConfig, flags}: AutoUpdateSources): AutoUpdateSettings {\n // Flags always take precedence over config\n if ('auto-updates' in flags) {\n const enabled = Boolean(flags['auto-updates'])\n return {\n enabled,\n issue: {flag: enabled ? '--auto-updates' : '--no-auto-updates', type: 'deprecated-flag'},\n }\n }\n\n const hasOldConfig = cliConfig && 'autoUpdates' in cliConfig\n\n const hasNewConfig =\n cliConfig &&\n 'deployment' in cliConfig &&\n cliConfig.deployment &&\n 'autoUpdates' in cliConfig.deployment\n\n if (hasNewConfig) {\n return {\n enabled: Boolean(cliConfig?.deployment?.autoUpdates),\n issue: hasOldConfig ? {type: 'conflicting-config'} : null,\n }\n }\n\n if (hasOldConfig) {\n return {enabled: Boolean(cliConfig?.autoUpdates), issue: {type: 'deprecated-config'}}\n }\n\n return {enabled: false, issue: null}\n}\n\n/**\n * The user-facing message for an auto-update configuration problem.\n * Shared by every surface that reports the issue (deploy warnings, dry-run\n * checks) so the wording has one home.\n *\n * @internal\n */\nexport function getAutoUpdateIssueMessage(issue: AutoUpdateIssue): string {\n switch (issue.type) {\n case 'conflicting-config': {\n return 'Found both `autoUpdates` (deprecated) and `deployment.autoUpdates` in sanity.cli.js/.ts. Please remove the deprecated top level `autoUpdates` config.'\n }\n case 'deprecated-config': {\n return 'The autoUpdates config has moved to deployment.autoUpdates.'\n }\n case 'deprecated-flag': {\n return `The ${issue.flag} flag is deprecated for deploy and build commands. Set the autoUpdates option in the deployment section of sanity.cli.ts or sanity.cli.js instead.`\n }\n }\n}\n\n/**\n * The styled before/after edit that migrates the deprecated top-level\n * `autoUpdates` to `deployment.autoUpdates`. Lives here so every surface that\n * reports the deprecated config (deploy warnings, dry-run checks) shows the\n * same migration hint.\n *\n * @internal\n */\nexport function getAutoUpdateMigrationHint(currentValue: unknown): string {\n return `Please update sanity.cli.ts or sanity.cli.js and make the following change:\n ${styleText('red', `- autoUpdates: ${currentValue},`)}\n ${styleText('green', `+ deployment: {autoUpdates: ${currentValue}}`)}\n`\n}\n\n/**\n * Resolves the auto-update setting and prints any configuration problem.\n * @remarks Throws an error if both the old and new auto update config are used; throws a warning if the old config is used, or if the auto updates flags are used.\n * @internal\n */\nexport function shouldAutoUpdate({\n cliConfig,\n flags,\n output,\n}: AutoUpdateSources & {output: Output}): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n switch (issue?.type) {\n case 'conflicting-config': {\n output.error(getAutoUpdateIssueMessage(issue), {exit: exitCodes.RUNTIME_ERROR})\n break\n }\n case 'deprecated-config': {\n output.warn(getAutoUpdateIssueMessage(issue))\n output.warn(getAutoUpdateMigrationHint(cliConfig.autoUpdates))\n break\n }\n case 'deprecated-flag': {\n output.warn(getAutoUpdateIssueMessage(issue))\n break\n }\n default: {\n break\n }\n }\n\n return enabled\n}\n"],"names":["styleText","exitCodes","resolveAutoUpdates","cliConfig","flags","enabled","Boolean","issue","flag","type","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","RUNTIME_ERROR","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAwBC,SAAS,QAAoB,mBAAkB;AA0BvE;;;;;CAKC,GACD,OAAO,SAASC,mBAAmB,EAACC,SAAS,EAAEC,KAAK,EAAoB;IACtE,2CAA2C;IAC3C,IAAI,kBAAkBA,OAAO;QAC3B,MAAMC,UAAUC,QAAQF,KAAK,CAAC,eAAe;QAC7C,OAAO;YACLC;YACAE,OAAO;gBAACC,MAAMH,UAAU,mBAAmB;gBAAqBI,MAAM;YAAiB;QACzF;IACF;IAEA,MAAMC,eAAeP,aAAa,iBAAiBA;IAEnD,MAAMQ,eACJR,aACA,gBAAgBA,aAChBA,UAAUS,UAAU,IACpB,iBAAiBT,UAAUS,UAAU;IAEvC,IAAID,cAAc;QAChB,OAAO;YACLN,SAASC,QAAQH,WAAWS,YAAYC;YACxCN,OAAOG,eAAe;gBAACD,MAAM;YAAoB,IAAI;QACvD;IACF;IAEA,IAAIC,cAAc;QAChB,OAAO;YAACL,SAASC,QAAQH,WAAWU;YAAcN,OAAO;gBAACE,MAAM;YAAmB;QAAC;IACtF;IAEA,OAAO;QAACJ,SAAS;QAAOE,OAAO;IAAI;AACrC;AAEA;;;;;;CAMC,GACD,OAAO,SAASO,0BAA0BP,KAAsB;IAC9D,OAAQA,MAAME,IAAI;QAChB,KAAK;YAAsB;gBACzB,OAAO;YACT;QACA,KAAK;YAAqB;gBACxB,OAAO;YACT;QACA,KAAK;YAAmB;gBACtB,OAAO,CAAC,IAAI,EAAEF,MAAMC,IAAI,CAAC,kJAAkJ,CAAC;YAC9K;IACF;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASO,2BAA2BC,YAAqB;IAC9D,OAAO,CAAC;EACR,EAAEhB,UAAU,OAAO,CAAC,gBAAgB,EAAEgB,aAAa,CAAC,CAAC,EAAE;EACvD,EAAEhB,UAAU,SAAS,CAAC,6BAA6B,EAAEgB,aAAa,CAAC,CAAC,EAAE;AACxE,CAAC;AACD;AAEA;;;;CAIC,GACD,OAAO,SAASC,iBAAiB,EAC/Bd,SAAS,EACTC,KAAK,EACLc,MAAM,EAC+B;IACrC,MAAM,EAACb,OAAO,EAAEE,KAAK,EAAC,GAAGL,mBAAmB;QAACC;QAAWC;IAAK;IAE7D,OAAQG,OAAOE;QACb,KAAK;YAAsB;gBACzBS,OAAOC,KAAK,CAACL,0BAA0BP,QAAQ;oBAACa,MAAMnB,UAAUoB,aAAa;gBAAA;gBAC7E;YACF;QACA,KAAK;YAAqB;gBACxBH,OAAOI,IAAI,CAACR,0BAA0BP;gBACtCW,OAAOI,IAAI,CAACP,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;YAAmB;gBACtBK,OAAOI,IAAI,CAACR,0BAA0BP;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOF;AACT"}
@@ -0,0 +1,165 @@
1
+ import { Args } from '@oclif/core';
2
+ import { CLIError } from '@oclif/core/errors';
3
+ import { exitCodes } from '@sanity/cli-core';
4
+ import { getErrorMessage } from '@sanity/cli-core/errors';
5
+ import { getMcpEndpoint } from '../../services/context.js';
6
+ import { getOrganizationFlag } from '../../util/sharedFlags.js';
7
+ import { formatKeyValue } from '../debug/output.js';
8
+ /**
9
+ * The `<name>` argument of commands that act on an existing endpoint
10
+ */ export const mcpEndpointNameArg = Args.string({
11
+ description: 'MCP endpoint name, as in its URL',
12
+ parse: parseEndpointName,
13
+ required: true
14
+ });
15
+ /**
16
+ * An argument `parse` that trims an endpoint name and rejects an empty one
17
+ */ export async function parseEndpointName(input) {
18
+ const trimmed = input.trim();
19
+ if (trimmed === '') throw new Error('The MCP endpoint name cannot be empty');
20
+ return trimmed;
21
+ }
22
+ /**
23
+ * Get an endpoint by name or ID, failing the command when the lookup fails or finds nothing
24
+ */ export async function findMcpEndpoint(organizationId, nameOrId) {
25
+ let endpoint;
26
+ try {
27
+ endpoint = await getMcpEndpoint(organizationId, nameOrId);
28
+ } catch (error) {
29
+ throw new CLIError(`Failed to get MCP endpoint: ${getErrorMessage(error)}`, {
30
+ exit: exitCodes.RUNTIME_ERROR
31
+ });
32
+ }
33
+ if (!endpoint) {
34
+ throw new CLIError(`MCP endpoint "${nameOrId}" not found`, {
35
+ exit: exitCodes.RUNTIME_ERROR
36
+ });
37
+ }
38
+ return endpoint;
39
+ }
40
+ /**
41
+ * The `--organization` flag of commands that act on an existing endpoint
42
+ */ export const mcpEndpointOrganizationFlag = getOrganizationFlag({
43
+ description: 'Organization the MCP endpoint belongs to',
44
+ semantics: 'override'
45
+ });
46
+ /**
47
+ * A flag `parse` that trims the value and rejects an empty one
48
+ */ export function parseNonEmpty(flag) {
49
+ return async (input)=>{
50
+ const trimmed = input.trim();
51
+ if (trimmed === '') {
52
+ throw new Error(`\`--${flag}\` cannot be empty if provided`);
53
+ }
54
+ return trimmed;
55
+ };
56
+ }
57
+ /**
58
+ * The API names a dataset source `<projectId>.<datasetName>`; the project comes from
59
+ * `--project` or the CLI configuration.
60
+ */ export function datasetSourceId(dataset, projectId) {
61
+ if (dataset === undefined) return undefined;
62
+ if (!projectId) {
63
+ throw new CLIError('Pass `--project` with `--dataset`, or run the command in a Sanity project directory.', {
64
+ exit: exitCodes.USAGE_ERROR
65
+ });
66
+ }
67
+ return `${projectId}.${dataset}`;
68
+ }
69
+ /**
70
+ * Apply source changes to an endpoint's current sources, or to none when creating one. The dataset
71
+ * keeps its settings until it is switched for another one; `dataset: null`
72
+ * removes it. Sources are rebuilt from their known fields, since the stored
73
+ * configuration may carry more. `notes` names the changes that were already in
74
+ * place, which leave the sources as they were.
75
+ */ export function editSources(current, changes) {
76
+ const notes = [];
77
+ const knowledgeBaseIds = current.filter((source)=>source.type === 'knowledge-base').map((source)=>source.id);
78
+ for (const id of new Set(changes.addKnowledgeBases)){
79
+ if (knowledgeBaseIds.includes(id)) {
80
+ notes.push(`Knowledge base "${id}" is already a source`);
81
+ } else {
82
+ knowledgeBaseIds.push(id);
83
+ }
84
+ }
85
+ for (const id of new Set(changes.removeKnowledgeBases)){
86
+ if (!knowledgeBaseIds.includes(id)) notes.push(`Knowledge base "${id}" is not a source`);
87
+ }
88
+ const sources = knowledgeBaseIds.filter((id)=>!changes.removeKnowledgeBases.includes(id)).map((id)=>({
89
+ id,
90
+ type: 'knowledge-base'
91
+ }));
92
+ const dataset = findDatasetSource(current);
93
+ if (changes.dataset === null && !dataset) notes.push('The endpoint has no dataset');
94
+ const datasetId = changes.dataset === undefined ? dataset?.id : changes.dataset;
95
+ if (datasetId) {
96
+ const kept = dataset?.id === datasetId ? {
97
+ perspective: dataset.perspective,
98
+ semanticSearch: dataset.semanticSearch,
99
+ workspace: dataset.workspace
100
+ } : {};
101
+ sources.push({
102
+ id: datasetId,
103
+ type: 'dataset',
104
+ ...kept,
105
+ ...changes.settings
106
+ });
107
+ }
108
+ return {
109
+ notes,
110
+ sources
111
+ };
112
+ }
113
+ function findDatasetSource(sources) {
114
+ return sources.find((source)=>source.type === 'dataset');
115
+ }
116
+ /**
117
+ * Key-value lines describing an endpoint, for `get`, `create` and `update` output
118
+ */ export function formatMcpEndpoint(endpoint) {
119
+ const padTo = 15 // "Knowledge bases" and "Semantic search" are the longest keys
120
+ ;
121
+ const knowledgeBaseIds = endpoint.sources.filter((source)=>source.type === 'knowledge-base').map((source)=>source.id);
122
+ const dataset = findDatasetSource(endpoint.sources);
123
+ const lines = [
124
+ formatKeyValue('ID', endpoint.id, {
125
+ padTo
126
+ }),
127
+ formatKeyValue('Name', endpoint.name, {
128
+ padTo
129
+ }),
130
+ formatKeyValue('Title', endpoint.title, {
131
+ padTo
132
+ }),
133
+ formatKeyValue('URL', endpoint.url, {
134
+ padTo
135
+ }),
136
+ formatKeyValue('Knowledge bases', knowledgeBaseIds.join(', ') || '-', {
137
+ padTo
138
+ }),
139
+ formatKeyValue('Dataset', dataset?.id ?? '-', {
140
+ padTo
141
+ })
142
+ ];
143
+ if (dataset) {
144
+ lines.push(formatKeyValue('Workspace', dataset.workspace ?? '-', {
145
+ padTo
146
+ }), formatKeyValue('Perspective', dataset.perspective ?? '-', {
147
+ padTo
148
+ }), formatKeyValue('Semantic search', formatSemanticSearch(dataset.semanticSearch), {
149
+ padTo
150
+ }));
151
+ }
152
+ lines.push(formatKeyValue('Instructions', endpoint.instructions ?? '-', {
153
+ padTo
154
+ }), formatKeyValue('GROQ filter', endpoint.groqFilter ?? '-', {
155
+ padTo
156
+ }));
157
+ return lines;
158
+ }
159
+ function formatSemanticSearch(semanticSearch) {
160
+ if (semanticSearch === true) return 'on';
161
+ if (semanticSearch === false) return 'off';
162
+ return '-';
163
+ }
164
+
165
+ //# sourceMappingURL=mcpEndpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/context/mcpEndpoint.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type Context} from '@sanity/client'\n\nimport {getMcpEndpoint} from '../../services/context.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\nimport {formatKeyValue} from '../debug/output.js'\n\ntype McpSource = Context.McpEndpoint['sources'][number]\ntype DatasetSource = Extract<McpSource, {type: 'dataset'}>\ntype McpSourceInput = Context.CreateMcpEndpointParams['sources'][number]\nexport type DatasetSettings = Partial<\n Pick<DatasetSource, 'perspective' | 'semanticSearch' | 'workspace'>\n>\n\n/**\n * The `<name>` argument of commands that act on an existing endpoint\n */\nexport const mcpEndpointNameArg = Args.string({\n description: 'MCP endpoint name, as in its URL',\n parse: parseEndpointName,\n required: true,\n})\n\n/**\n * An argument `parse` that trims an endpoint name and rejects an empty one\n */\nexport async function parseEndpointName(input: string): Promise<string> {\n const trimmed = input.trim()\n if (trimmed === '') throw new Error('The MCP endpoint name cannot be empty')\n return trimmed\n}\n\n/**\n * Get an endpoint by name or ID, failing the command when the lookup fails or finds nothing\n */\nexport async function findMcpEndpoint(\n organizationId: string,\n nameOrId: string,\n): Promise<Context.McpEndpoint> {\n let endpoint\n try {\n endpoint = await getMcpEndpoint(organizationId, nameOrId)\n } catch (error) {\n throw new CLIError(`Failed to get MCP endpoint: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n if (!endpoint) {\n throw new CLIError(`MCP endpoint \"${nameOrId}\" not found`, {exit: exitCodes.RUNTIME_ERROR})\n }\n return endpoint\n}\n\n/**\n * The `--organization` flag of commands that act on an existing endpoint\n */\nexport const mcpEndpointOrganizationFlag = getOrganizationFlag({\n description: 'Organization the MCP endpoint belongs to',\n semantics: 'override',\n})\n\n/**\n * A flag `parse` that trims the value and rejects an empty one\n */\nexport function parseNonEmpty(flag: string): (input: string) => Promise<string> {\n return async (input) => {\n const trimmed = input.trim()\n if (trimmed === '') {\n throw new Error(`\\`--${flag}\\` cannot be empty if provided`)\n }\n return trimmed\n }\n}\n\n/**\n * The API names a dataset source `<projectId>.<datasetName>`; the project comes from\n * `--project` or the CLI configuration.\n */\nexport function datasetSourceId(\n dataset: string | undefined,\n projectId: string | undefined,\n): string | undefined {\n if (dataset === undefined) return undefined\n if (!projectId) {\n throw new CLIError(\n 'Pass `--project` with `--dataset`, or run the command in a Sanity project directory.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n return `${projectId}.${dataset}`\n}\n\n/**\n * Apply source changes to an endpoint's current sources, or to none when creating one. The dataset\n * keeps its settings until it is switched for another one; `dataset: null`\n * removes it. Sources are rebuilt from their known fields, since the stored\n * configuration may carry more. `notes` names the changes that were already in\n * place, which leave the sources as they were.\n */\nexport function editSources(\n current: McpSource[],\n changes: {\n addKnowledgeBases: string[]\n dataset: string | null | undefined\n removeKnowledgeBases: string[]\n settings: DatasetSettings\n },\n): {notes: string[]; sources: McpSourceInput[]} {\n const notes: string[] = []\n const knowledgeBaseIds = current\n .filter((source) => source.type === 'knowledge-base')\n .map((source) => source.id)\n\n for (const id of new Set(changes.addKnowledgeBases)) {\n if (knowledgeBaseIds.includes(id)) {\n notes.push(`Knowledge base \"${id}\" is already a source`)\n } else {\n knowledgeBaseIds.push(id)\n }\n }\n for (const id of new Set(changes.removeKnowledgeBases)) {\n if (!knowledgeBaseIds.includes(id)) notes.push(`Knowledge base \"${id}\" is not a source`)\n }\n const sources: McpSourceInput[] = knowledgeBaseIds\n .filter((id) => !changes.removeKnowledgeBases.includes(id))\n .map((id) => ({id, type: 'knowledge-base'}))\n\n const dataset = findDatasetSource(current)\n if (changes.dataset === null && !dataset) notes.push('The endpoint has no dataset')\n const datasetId = changes.dataset === undefined ? dataset?.id : changes.dataset\n if (datasetId) {\n const kept =\n dataset?.id === datasetId\n ? {\n perspective: dataset.perspective,\n semanticSearch: dataset.semanticSearch,\n workspace: dataset.workspace,\n }\n : {}\n sources.push({id: datasetId, type: 'dataset', ...kept, ...changes.settings})\n }\n\n return {notes, sources}\n}\n\nfunction findDatasetSource(sources: McpSource[]): DatasetSource | undefined {\n return sources.find((source): source is DatasetSource => source.type === 'dataset')\n}\n\n/**\n * Key-value lines describing an endpoint, for `get`, `create` and `update` output\n */\nexport function formatMcpEndpoint(endpoint: Context.McpEndpoint): string[] {\n const padTo = 15 // \"Knowledge bases\" and \"Semantic search\" are the longest keys\n const knowledgeBaseIds = endpoint.sources\n .filter((source) => source.type === 'knowledge-base')\n .map((source) => source.id)\n const dataset = findDatasetSource(endpoint.sources)\n\n const lines = [\n formatKeyValue('ID', endpoint.id, {padTo}),\n formatKeyValue('Name', endpoint.name, {padTo}),\n formatKeyValue('Title', endpoint.title, {padTo}),\n formatKeyValue('URL', endpoint.url, {padTo}),\n formatKeyValue('Knowledge bases', knowledgeBaseIds.join(', ') || '-', {padTo}),\n formatKeyValue('Dataset', dataset?.id ?? '-', {padTo}),\n ]\n if (dataset) {\n lines.push(\n formatKeyValue('Workspace', dataset.workspace ?? '-', {padTo}),\n formatKeyValue('Perspective', dataset.perspective ?? '-', {padTo}),\n formatKeyValue('Semantic search', formatSemanticSearch(dataset.semanticSearch), {padTo}),\n )\n }\n lines.push(\n formatKeyValue('Instructions', endpoint.instructions ?? '-', {padTo}),\n formatKeyValue('GROQ filter', endpoint.groqFilter ?? '-', {padTo}),\n )\n return lines\n}\n\nfunction formatSemanticSearch(semanticSearch: boolean | null | undefined): string {\n if (semanticSearch === true) return 'on'\n if (semanticSearch === false) return 'off'\n return '-'\n}\n"],"names":["Args","CLIError","exitCodes","getErrorMessage","getMcpEndpoint","getOrganizationFlag","formatKeyValue","mcpEndpointNameArg","string","description","parse","parseEndpointName","required","input","trimmed","trim","Error","findMcpEndpoint","organizationId","nameOrId","endpoint","error","exit","RUNTIME_ERROR","mcpEndpointOrganizationFlag","semantics","parseNonEmpty","flag","datasetSourceId","dataset","projectId","undefined","USAGE_ERROR","editSources","current","changes","notes","knowledgeBaseIds","filter","source","type","map","id","Set","addKnowledgeBases","includes","push","removeKnowledgeBases","sources","findDatasetSource","datasetId","kept","perspective","semanticSearch","workspace","settings","find","formatMcpEndpoint","padTo","lines","name","title","url","join","formatSemanticSearch","instructions","groqFilter"],"mappings":"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"}
@@ -1,5 +1,12 @@
1
+ import { CLIError } from '@oclif/core/errors';
2
+ import { exitCodes } from '@sanity/cli-core';
1
3
  import { promptForOrganization } from '../../prompts/promptForOrganization.js';
2
- /** The organization could not be determined and prompting is not possible. */ export class MissingOrganizationError extends Error {
4
+ /** The organization could not be determined and prompting is not possible. */ export class MissingOrganizationError extends CLIError {
5
+ constructor(message){
6
+ super(message, {
7
+ exit: exitCodes.USAGE_ERROR
8
+ });
9
+ }
3
10
  }
4
11
  /**
5
12
  * Resolve the organization to operate on: the `--organization` flag wins,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/context/resolveOrganizationId.ts"],"sourcesContent":["import {promptForOrganization} from '../../prompts/promptForOrganization.js'\n\n/** The organization could not be determined and prompting is not possible. */\nexport class MissingOrganizationError extends Error {}\n\n/**\n * Resolve the organization to operate on: the `--organization` flag wins,\n * then the CLI config's `app.organizationId`, then an interactive prompt.\n */\nexport async function resolveOrganizationId(options: {\n configuredOrganizationId: string | undefined\n flagOrganizationId: string | undefined\n unattended: boolean\n}): Promise<string> {\n const {configuredOrganizationId, flagOrganizationId, unattended} = options\n\n if (flagOrganizationId) return flagOrganizationId\n if (configuredOrganizationId) return configuredOrganizationId\n\n if (unattended) {\n throw new MissingOrganizationError(\n 'Organization ID is required. Provide it with the --organization flag.',\n )\n }\n\n return promptForOrganization()\n}\n"],"names":["promptForOrganization","MissingOrganizationError","Error","resolveOrganizationId","options","configuredOrganizationId","flagOrganizationId","unattended"],"mappings":"AAAA,SAAQA,qBAAqB,QAAO,yCAAwC;AAE5E,4EAA4E,GAC5E,OAAO,MAAMC,iCAAiCC;AAAO;AAErD;;;CAGC,GACD,OAAO,eAAeC,sBAAsBC,OAI3C;IACC,MAAM,EAACC,wBAAwB,EAAEC,kBAAkB,EAAEC,UAAU,EAAC,GAAGH;IAEnE,IAAIE,oBAAoB,OAAOA;IAC/B,IAAID,0BAA0B,OAAOA;IAErC,IAAIE,YAAY;QACd,MAAM,IAAIN,yBACR;IAEJ;IAEA,OAAOD;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/context/resolveOrganizationId.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\n\nimport {promptForOrganization} from '../../prompts/promptForOrganization.js'\n\n/** The organization could not be determined and prompting is not possible. */\nexport class MissingOrganizationError extends CLIError {\n constructor(message: string) {\n super(message, {exit: exitCodes.USAGE_ERROR})\n }\n}\n\n/**\n * Resolve the organization to operate on: the `--organization` flag wins,\n * then the CLI config's `app.organizationId`, then an interactive prompt.\n */\nexport async function resolveOrganizationId(options: {\n configuredOrganizationId: string | undefined\n flagOrganizationId: string | undefined\n unattended: boolean\n}): Promise<string> {\n const {configuredOrganizationId, flagOrganizationId, unattended} = options\n\n if (flagOrganizationId) return flagOrganizationId\n if (configuredOrganizationId) return configuredOrganizationId\n\n if (unattended) {\n throw new MissingOrganizationError(\n 'Organization ID is required. Provide it with the --organization flag.',\n )\n }\n\n return promptForOrganization()\n}\n"],"names":["CLIError","exitCodes","promptForOrganization","MissingOrganizationError","message","exit","USAGE_ERROR","resolveOrganizationId","options","configuredOrganizationId","flagOrganizationId","unattended"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,SAAQC,SAAS,QAAO,mBAAkB;AAE1C,SAAQC,qBAAqB,QAAO,yCAAwC;AAE5E,4EAA4E,GAC5E,OAAO,MAAMC,iCAAiCH;IAC5C,YAAYI,OAAe,CAAE;QAC3B,KAAK,CAACA,SAAS;YAACC,MAAMJ,UAAUK,WAAW;QAAA;IAC7C;AACF;AAEA;;;CAGC,GACD,OAAO,eAAeC,sBAAsBC,OAI3C;IACC,MAAM,EAACC,wBAAwB,EAAEC,kBAAkB,EAAEC,UAAU,EAAC,GAAGH;IAEnE,IAAIE,oBAAoB,OAAOA;IAC/B,IAAID,0BAA0B,OAAOA;IAErC,IAAIE,YAAY;QACd,MAAM,IAAIR,yBACR;IAEJ;IAEA,OAAOD;AACT"}
@@ -7,7 +7,7 @@ import { getErrorMessage } from '@sanity/cli-core/errors';
7
7
  import { getCoreAppUrl } from '@sanity/cli-core/util';
8
8
  import { confirm, spinner } from '@sanity/cli-core/ux';
9
9
  import { resolveAppEntry } from '@sanity/workbench-cli/build';
10
- import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
10
+ import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, selectWorkbenchAppId, 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';
@@ -105,6 +105,7 @@ export function deployApp(options) {
105
105
  let application = null;
106
106
  let appCreated = false;
107
107
  let workbenchApp;
108
+ let targetAppId = appId;
108
109
  if (flags.external) {
109
110
  reporter.report({
110
111
  message: EXTERNAL_APP_NOT_SUPPORTED,
@@ -112,8 +113,14 @@ export function deployApp(options) {
112
113
  status: 'fail'
113
114
  });
114
115
  } else if (deployApplication && workbench) {
115
- workbenchApp = (await checkAppTarget(reporter, {
116
+ targetAppId = await selectWorkbenchAppId({
116
117
  appId,
118
+ flags,
119
+ organizationId,
120
+ type: 'coreApp'
121
+ });
122
+ workbenchApp = (await checkAppTarget(reporter, {
123
+ appId: targetAppId,
117
124
  hasAppView,
118
125
  isWorkbenchApp: true,
119
126
  organizationId,
@@ -141,7 +148,7 @@ export function deployApp(options) {
141
148
  const appIcon = !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
142
149
  // Create the app before the build so the bundle carries its real id. A
143
150
  // redeploy already has it from `deployment.appId`; a dry run skips creation.
144
- let applicationId = appId;
151
+ let applicationId = targetAppId;
145
152
  let applicationCreated = false;
146
153
  let rollbackApp;
147
154
  if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {
@@ -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 {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
+ {"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 selectWorkbenchAppId,\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 let targetAppId = appId\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 targetAppId = await selectWorkbenchAppId({appId, flags, organizationId, type: 'coreApp'})\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId: targetAppId,\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 = targetAppId\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","selectWorkbenchAppId","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","targetAppId","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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"}
@@ -5,7 +5,7 @@ import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build
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, getWorkbenchUrl, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
8
+ import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, selectWorkbenchAppId, 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';
@@ -67,6 +67,7 @@ export function deployStudio(options) {
67
67
  let studioCreated = false;
68
68
  let workbenchApp;
69
69
  let externalUrl;
70
+ let targetAppId = appId;
70
71
  if (workbench) {
71
72
  reporter.report(organizationId ? {
72
73
  message: `Organization: ${organizationId}`,
@@ -76,15 +77,21 @@ export function deployStudio(options) {
76
77
  solution: 'Add `app.organizationId` to sanity.cli.ts',
77
78
  status: 'fail'
78
79
  });
79
- workbenchApp = (await checkStudioTarget(reporter, {
80
+ targetAppId = await selectWorkbenchAppId({
80
81
  appId,
82
+ flags,
83
+ organizationId,
84
+ type: 'studio'
85
+ });
86
+ workbenchApp = (await checkStudioTarget(reporter, {
87
+ appId: targetAppId,
81
88
  isWorkbenchApp: true,
82
89
  organizationId,
83
90
  slug: workbench.slug,
84
91
  title: appTitle
85
92
  }))?.application;
86
93
  if (isExternal) externalUrl = checkExternalUrl(reporter, {
87
- appId,
94
+ appId: targetAppId,
88
95
  url: flags.url
89
96
  });
90
97
  } else {
@@ -110,7 +117,7 @@ export function deployStudio(options) {
110
117
  const appIcon = !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined;
111
118
  // Create the studio before the build so the bundle carries its real id. A
112
119
  // redeploy already has it from `deployment.appId`; a dry run skips creation.
113
- let applicationId = appId;
120
+ let applicationId = targetAppId;
114
121
  let applicationCreated = false;
115
122
  let rollbackApp;
116
123
  if (!dryRun && workbench && organizationId && !applicationId) {