@sanity/cli 7.15.1 → 7.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +87 -0
  2. package/dist/actions/build/shouldAutoUpdate.js +28 -5
  3. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  4. package/dist/actions/deploy/deployApp.js +4 -8
  5. package/dist/actions/deploy/deployApp.js.map +1 -1
  6. package/dist/actions/deploy/deployChecks.js +49 -31
  7. package/dist/actions/deploy/deployChecks.js.map +1 -1
  8. package/dist/actions/deploy/deployRunner.js +1 -1
  9. package/dist/actions/deploy/deployRunner.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +12 -10
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/deploy/deploymentPlan.js +2 -2
  13. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  14. package/dist/actions/deploy/resolveDeployTarget.js +13 -13
  15. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  16. package/dist/actions/init/bootstrapLocalTemplate.js +2 -3
  17. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  18. package/dist/actions/init/createAppCliConfig.js.map +1 -1
  19. package/dist/actions/init/createCliConfig.js.map +1 -1
  20. package/dist/actions/init/initNextJs.js +1 -1
  21. package/dist/actions/init/initNextJs.js.map +1 -1
  22. package/dist/actions/init/initStudio.js +10 -6
  23. package/dist/actions/init/initStudio.js.map +1 -1
  24. package/dist/actions/init/templates/appSanityUi.js +1 -1
  25. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  26. package/dist/actions/init/templates/getStarted.js +2 -2
  27. package/dist/actions/init/templates/getStarted.js.map +1 -1
  28. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js +4 -4
  29. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js.map +1 -1
  30. package/dist/actions/init/templates/shopify.js +5 -5
  31. package/dist/actions/init/templates/shopify.js.map +1 -1
  32. package/dist/actions/init/templates/shopifyOnline.js +3 -3
  33. package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
  34. package/dist/actions/manifest/extractCoreAppManifest.js +7 -7
  35. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  36. package/dist/actions/scaffold/createFrontend.js +107 -0
  37. package/dist/actions/scaffold/createFrontend.js.map +1 -0
  38. package/dist/actions/scaffold/scaffoldProject.js +202 -0
  39. package/dist/actions/scaffold/scaffoldProject.js.map +1 -0
  40. package/dist/commands/backups/list.js +1 -1
  41. package/dist/commands/backups/list.js.map +1 -1
  42. package/dist/commands/migrations/list.js +1 -1
  43. package/dist/commands/migrations/list.js.map +1 -1
  44. package/dist/commands/migrations/run.js +1 -1
  45. package/dist/commands/migrations/run.js.map +1 -1
  46. package/dist/commands/new.js +309 -0
  47. package/dist/commands/new.js.map +1 -0
  48. package/dist/commands/organizations/list.js +1 -1
  49. package/dist/commands/organizations/list.js.map +1 -1
  50. package/dist/commands/projects/unclaimed.js +205 -0
  51. package/dist/commands/projects/unclaimed.js.map +1 -0
  52. package/dist/commands/tokens/list.js +1 -1
  53. package/dist/commands/tokens/list.js.map +1 -1
  54. package/dist/commands/users/list.js +5 -1
  55. package/dist/commands/users/list.js.map +1 -1
  56. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +4 -0
  57. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  58. package/dist/exports/runtime.d.ts +24 -0
  59. package/dist/exports/runtime.js.map +1 -1
  60. package/dist/services/mintProject.js +91 -0
  61. package/dist/services/mintProject.js.map +1 -0
  62. package/dist/services/projects.js +19 -0
  63. package/dist/services/projects.js.map +1 -1
  64. package/dist/util/formatClaimDeadline.js +15 -0
  65. package/dist/util/formatClaimDeadline.js.map +1 -0
  66. package/dist/util/mintProjectConstants.js +6 -0
  67. package/dist/util/mintProjectConstants.js.map +1 -0
  68. package/dist/util/newCommandSplash.js +27 -0
  69. package/dist/util/newCommandSplash.js.map +1 -0
  70. package/dist/util/packageManager/installPackages.js +57 -28
  71. package/dist/util/packageManager/installPackages.js.map +1 -1
  72. package/dist/util/unclaimedProjects.js +105 -0
  73. package/dist/util/unclaimedProjects.js.map +1 -0
  74. package/oclif.config.js +1 -0
  75. package/oclif.manifest.json +111 -1
  76. package/package.json +6 -6
  77. package/templates/get-started/plugins/sanity-plugin-tutorial/GetStartedTutorial.tsx +1 -1
  78. package/templates/shopify/components/inputs/CollectionHidden.tsx +1 -1
  79. package/templates/shopify/components/inputs/ProductHidden.tsx +1 -1
  80. package/templates/shopify/components/inputs/ProductVariantHidden.tsx +1 -1
  81. package/templates/shopify/components/inputs/ProxyString.tsx +1 -1
  82. package/templates/shopify/components/media/ShopifyDocumentStatus.tsx +3 -1
  83. package/templates/shopify/constants.ts +3 -1
  84. package/templates/shopify/plugins/customDocumentActions/shopifyDelete.tsx +1 -1
  85. package/templates/shopify/plugins/customDocumentActions/shopifyLink.ts +1 -1
  86. package/templates/shopify/schemaTypes/documents/collection.tsx +1 -1
  87. package/templates/shopify/schemaTypes/documents/colorTheme.tsx +1 -1
  88. package/templates/shopify/schemaTypes/documents/page.ts +1 -1
  89. package/templates/shopify/schemaTypes/documents/product.tsx +1 -1
  90. package/templates/shopify/schemaTypes/documents/productVariant.tsx +1 -1
  91. package/templates/shopify/schemaTypes/objects/collection/collectionGroupType.ts +1 -1
  92. package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
  93. package/templates/shopify/schemaTypes/objects/link/linkEmailType.tsx +1 -1
  94. package/templates/shopify/schemaTypes/objects/link/linkExternalType.tsx +1 -1
  95. package/templates/shopify/schemaTypes/objects/link/linkInternalType.tsx +1 -1
  96. package/templates/shopify/schemaTypes/objects/link/linkProductType.tsx +1 -1
  97. package/templates/shopify/schemaTypes/objects/module/accordionType.ts +1 -1
  98. package/templates/shopify/schemaTypes/objects/module/callToActionType.tsx +2 -1
  99. package/templates/shopify/schemaTypes/objects/module/calloutType.ts +1 -1
  100. package/templates/shopify/schemaTypes/objects/module/collectionReferenceType.tsx +1 -1
  101. package/templates/shopify/schemaTypes/objects/module/gridType.ts +1 -1
  102. package/templates/shopify/schemaTypes/objects/module/imageFeatureType.ts +1 -1
  103. package/templates/shopify/schemaTypes/objects/module/imageFeaturesType.tsx +1 -1
  104. package/templates/shopify/schemaTypes/objects/module/instagramType.ts +1 -1
  105. package/templates/shopify/schemaTypes/objects/module/productFeaturesType.tsx +1 -1
  106. package/templates/shopify/schemaTypes/objects/module/productReferenceType.tsx +1 -1
  107. package/templates/shopify/schemaTypes/objects/shopify/collectionRuleType.tsx +1 -1
  108. package/templates/shopify/schemaTypes/objects/shopify/optionType.tsx +1 -1
  109. package/templates/shopify/schemaTypes/objects/shopify/productWithVariantType.tsx +1 -1
  110. package/templates/shopify/schemaTypes/singletons/homeType.ts +1 -1
  111. package/templates/shopify/schemaTypes/singletons/settingsType.ts +5 -1
  112. package/templates/shopify/structure/pageStructure.ts +1 -1
  113. package/templates/shopify/structure/productStructure.ts +1 -1
  114. package/templates/shopify-online-storefront/components/inputs/CollectionHidden.tsx +1 -1
  115. package/templates/shopify-online-storefront/components/inputs/ProductHidden.tsx +1 -1
  116. package/templates/shopify-online-storefront/components/inputs/ProductVariantHidden.tsx +1 -1
  117. package/templates/shopify-online-storefront/components/inputs/ProxyString.tsx +1 -1
  118. package/templates/shopify-online-storefront/components/media/ShopifyDocumentStatus.tsx +3 -1
  119. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyDelete.tsx +1 -1
  120. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyLink.ts +1 -1
  121. package/templates/shopify-online-storefront/schemaTypes/documents/collection.tsx +1 -1
  122. package/templates/shopify-online-storefront/schemaTypes/documents/product.tsx +1 -1
  123. package/templates/shopify-online-storefront/schemaTypes/documents/productVariant.tsx +1 -1
  124. package/templates/shopify-online-storefront/schemaTypes/objects/accordion.ts +1 -1
  125. package/templates/shopify-online-storefront/schemaTypes/objects/callout.ts +1 -1
  126. package/templates/shopify-online-storefront/schemaTypes/objects/option.ts +1 -1
  127. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollectionRule.tsx +1 -1
  128. package/templates/shopify-online-storefront/structure/productStructure.ts +1 -1
package/README.md CHANGED
@@ -95,6 +95,7 @@ Code for sanity cli
95
95
  - [`sanity migrations create [TITLE]`](#sanity-migrations-create-title)
96
96
  - [`sanity migrations list`](#sanity-migrations-list)
97
97
  - [`sanity migrations run [ID]`](#sanity-migrations-run-id)
98
+ - [`sanity new [PROJECTNAME]`](#sanity-new-projectname)
98
99
  - [`sanity openapi get SLUG`](#sanity-openapi-get-slug)
99
100
  - [`sanity openapi list`](#sanity-openapi-list)
100
101
  - [`sanity organizations create`](#sanity-organizations-create)
@@ -105,6 +106,7 @@ Code for sanity cli
105
106
  - [`sanity preview [OUTPUTDIR]`](#sanity-preview-outputdir)
106
107
  - [`sanity projects create [PROJECTNAME]`](#sanity-projects-create-projectname)
107
108
  - [`sanity projects list`](#sanity-projects-list)
109
+ - [`sanity projects unclaimed`](#sanity-projects-unclaimed)
108
110
  - [`sanity schemas delete`](#sanity-schemas-delete)
109
111
  - [`sanity schemas deploy`](#sanity-schemas-deploy)
110
112
  - [`sanity schemas extract`](#sanity-schemas-extract)
@@ -2964,6 +2966,67 @@ EXAMPLES
2964
2966
  $ sanity migrations run <id> --from-export=production.tar.gz --no-dry-run --project xyz --dataset staging
2965
2967
  ```
2966
2968
 
2969
+ ## `sanity new [PROJECTNAME]`
2970
+
2971
+ Create a Sanity project without an account, and claim it within 72 hours to keep it.
2972
+
2973
+ ```
2974
+ USAGE
2975
+ $ sanity new [PROJECTNAME] [--json] [--scaffold] [-y]
2976
+
2977
+ ARGUMENTS
2978
+ [PROJECTNAME] Display name for the new project
2979
+
2980
+ FLAGS
2981
+ -y, --yes Skip prompts and use defaults (project: "My Sanity project")
2982
+ --[no-]scaffold Set up a Studio in ./sanity and a Next.js website in ./web (on by default)
2983
+
2984
+ GLOBAL FLAGS
2985
+ --json Format output as json.
2986
+
2987
+ DESCRIPTION
2988
+ Create a Sanity project without an account, and claim it within 72 hours to keep it.
2989
+
2990
+ Sets up two folders here: ./sanity, a Studio where you write and edit your
2991
+ content, and ./web, a Next.js website that reads it. Both are already
2992
+ connected to your new project, so you can start them straight away. Use
2993
+ --no-scaffold if you just want the project and nothing else.
2994
+
2995
+ The project is real and works immediately, but it is only yours for 72 hours.
2996
+ Claim it with a Sanity account before the deadline and everything you have
2997
+ built stays exactly as it is. Claiming is free and takes about a minute. Miss
2998
+ the deadline and the project and its content are deleted.
2999
+
3000
+ Two things to keep private: the claim link, because anyone who opens it
3001
+ becomes the owner, and the access token saved in ./sanity/.env.local and
3002
+ ./web/.env.local, because it can read and change everything in the project.
3003
+ Keep both env files out of git, and never put the token in code that runs in
3004
+ the browser.
3005
+
3006
+ Fetch https://sanity.new for full instructions, or point your AI agent at it.
3007
+
3008
+ EXAMPLES
3009
+ Create a project with a Studio and a website
3010
+
3011
+ $ sanity new
3012
+
3013
+ Create a project called "My New Project"
3014
+
3015
+ $ sanity new "My New Project"
3016
+
3017
+ Create a project without being asked anything
3018
+
3019
+ $ sanity new --yes
3020
+
3021
+ Create the project only, with no Studio or website
3022
+
3023
+ $ sanity new --no-scaffold
3024
+
3025
+ Create a project and print its details as JSON
3026
+
3027
+ $ sanity new --json
3028
+ ```
3029
+
2967
3030
  ## `sanity openapi get SLUG`
2968
3031
 
2969
3032
  Get an OpenAPI specification by slug
@@ -3255,6 +3318,30 @@ EXAMPLES
3255
3318
  $ sanity projects list --sort=members --order=asc
3256
3319
  ```
3257
3320
 
3321
+ ## `sanity projects unclaimed`
3322
+
3323
+ Recover details for unclaimed projects created on this machine
3324
+
3325
+ ```
3326
+ USAGE
3327
+ $ sanity projects unclaimed [--project-id <value>]
3328
+
3329
+ FLAGS
3330
+ --project-id=<value> Project ID to recover
3331
+
3332
+ DESCRIPTION
3333
+ Recover details for unclaimed projects created on this machine
3334
+
3335
+ EXAMPLES
3336
+ List locally recorded unclaimed projects
3337
+
3338
+ $ sanity projects unclaimed
3339
+
3340
+ Show recovery details for one project
3341
+
3342
+ $ sanity projects unclaimed --project-id abc123
3343
+ ```
3344
+
3258
3345
  ## `sanity schemas delete`
3259
3346
 
3260
3347
  Delete schema documents by id
@@ -1,12 +1,30 @@
1
1
  import { styleText } from 'node:util';
2
+ import { isWorkbenchApp } from '@sanity/workbench-cli';
2
3
  /**
3
- * Owns the auto-update rules: flag-over-config precedence, the deprecated
4
- * top-level `autoUpdates` config, and the old/new config conflict.
5
- * Returns plain facts so each surface (deploy warnings, dry-run checks)
6
- * decides its own presentation.
4
+ * Owns the auto-update rules and returns plain facts, so each surface (build,
5
+ * dev, deploy warnings, dry-run checks) decides its own presentation.
7
6
  *
8
7
  * @internal
9
- */ export function resolveAutoUpdates({ cliConfig, flags }) {
8
+ */ export function resolveAutoUpdates(sources) {
9
+ const settings = resolveConfiguredAutoUpdates(sources);
10
+ // A workbench app takes `sanity` from the shell's shared runtime, so it has no
11
+ // version of its own to pin.
12
+ // TODO(SDK-1045): confirm the long-term story with the studio team.
13
+ if (settings.enabled && isWorkbenchApp(sources.cliConfig?.app)) {
14
+ // A config conflict still fails — it's a problem with the config itself.
15
+ return settings.issue?.type === 'conflicting-config' ? {
16
+ enabled: false,
17
+ issue: settings.issue
18
+ } : {
19
+ enabled: false,
20
+ issue: {
21
+ type: 'unsupported'
22
+ }
23
+ };
24
+ }
25
+ return settings;
26
+ }
27
+ function resolveConfiguredAutoUpdates({ cliConfig, flags }) {
10
28
  // Flags always take precedence over config
11
29
  if ('auto-updates' in flags) {
12
30
  const enabled = Boolean(flags['auto-updates']);
@@ -61,6 +79,10 @@ import { styleText } from 'node:util';
61
79
  {
62
80
  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.`;
63
81
  }
82
+ case 'unsupported':
83
+ {
84
+ return "Auto-updates aren't supported yet — using the installed package versions";
85
+ }
64
86
  }
65
87
  }
66
88
  /**
@@ -100,6 +122,7 @@ import { styleText } from 'node:util';
100
122
  break;
101
123
  }
102
124
  case 'deprecated-flag':
125
+ case 'unsupported':
103
126
  {
104
127
  output.warn(getAutoUpdateIssueMessage(issue));
105
128
  break;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, 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: flag-over-config precedence, the deprecated\n * top-level `autoUpdates` config, and the old/new config conflict.\n * Returns plain facts so each surface (deploy warnings, dry-run checks)\n * 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: 1})\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","resolveAutoUpdates","cliConfig","flags","enabled","Boolean","issue","flag","type","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AA4BnC;;;;;;;CAOC,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,EAAEf,UAAU,OAAO,CAAC,gBAAgB,EAAEe,aAAa,CAAC,CAAC,EAAE;EACvD,EAAEf,UAAU,SAAS,CAAC,6BAA6B,EAAEe,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,MAAM;gBAAC;gBACvD;YACF;QACA,KAAK;YAAqB;gBACxBF,OAAOG,IAAI,CAACP,0BAA0BP;gBACtCW,OAAOG,IAAI,CAACN,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;YAAmB;gBACtBK,OAAOG,IAAI,CAACP,0BAA0BP;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOF;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/build/shouldAutoUpdate.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type CliConfig, 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: 1})\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","isWorkbenchApp","resolveAutoUpdates","sources","settings","resolveConfiguredAutoUpdates","enabled","cliConfig","app","issue","type","flags","Boolean","flag","hasOldConfig","hasNewConfig","deployment","autoUpdates","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","currentValue","shouldAutoUpdate","output","error","exit","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAGnC,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,EAAEpB,UAAU,OAAO,CAAC,gBAAgB,EAAEoB,aAAa,CAAC,CAAC,EAAE;EACvD,EAAEpB,UAAU,SAAS,CAAC,6BAA6B,EAAEoB,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,MAAM;gBAAC;gBACvD;YACF;QACA,KAAK;YAAqB;gBACxBF,OAAOG,IAAI,CAACP,0BAA0BT;gBACtCa,OAAOG,IAAI,CAACN,2BAA2BZ,UAAUU,WAAW;gBAC5D;YACF;QACA,KAAK;QACL,KAAK;YAAe;gBAClBK,OAAOG,IAAI,CAACP,0BAA0BT;gBACtC;YACF;QACA;YAAS;gBACP;YACF;IACF;IAEA,OAAOH;AACT"}
@@ -5,7 +5,7 @@ import { exitCodes } from '@sanity/cli-core';
5
5
  import { getErrorMessage } from '@sanity/cli-core/errors';
6
6
  import { getCoreAppUrl } from '@sanity/cli-core/util';
7
7
  import { spinner } from '@sanity/cli-core/ux';
8
- import { buildExposes, createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, resolveInstallationId, summarizeConfig } from '@sanity/workbench-cli/deploy';
8
+ import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, resolveInstallationId, summarizeConfig } from '@sanity/workbench-cli/deploy';
9
9
  import { pack } from 'tar-fs';
10
10
  import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
11
11
  import { getAppId } from '../../util/appId.js';
@@ -37,7 +37,7 @@ export function deployApp(options) {
37
37
  // application; anything that exposes a view or service still ships one.
38
38
  const deploySingletonConfig = workbench?.deploySingletonConfig ?? false;
39
39
  const deployApplication = !workbench || workbench.hasInterfaces;
40
- const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name : '';
40
+ const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug : '';
41
41
  // A federated app with no entry, view or service would ship a remote with
42
42
  // nothing to load — reported first so it fails before any prompt or API call.
43
43
  if (workbench) {
@@ -241,14 +241,10 @@ export function deployApp(options) {
241
241
  // so this only ships the deployment; plain coreApps use user-applications below.
242
242
  if (workbench && organizationId && applicationId) {
243
243
  await deployWorkbenchApp({
244
+ app: cliConfig.app,
244
245
  applicationId,
245
246
  icon: appIcon,
246
- interfaces: buildExposes(workbench, {
247
- appName: workbench.name,
248
- appTitle,
249
- exposesAppView: workbench.entry !== undefined,
250
- version
251
- }),
247
+ isApp: true,
252
248
  isAutoUpdating,
253
249
  // Once the deployment is live, a metadata-sync or later config failure
254
250
  // must not delete the app.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n buildExposes,\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n summarizeConfig,\n} from '@sanity/workbench-cli/deploy'\nimport {pack} from 'tar-fs'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '../manifest/extractCoreAppManifest.js'\nimport {type CoreAppManifest} from '../manifest/types.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportExposes} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A singleton (the Media Library) persists its config instead of hosting an\n // application; anything that exposes a view or service still ships one.\n const deploySingletonConfig = workbench?.deploySingletonConfig ?? false\n const deployApplication = !workbench || workbench.hasInterfaces\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deploySingletonConfig) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n ;({applicationId, rollback: rollbackApp} = await createCoreApp({\n isSingleton: workbench.isSingleton,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n }))\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({isWorkbenchApp: workbench !== null, reporter, sourceDir})\n\n // Workbench apps ship their icon straight to Brett (below) and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let config: string | undefined\n const configAppType = workbench?.config?.appType\n if (deploySingletonConfig && organizationId && workbench?.config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n config = summarizeConfig(workbench.config)\n reporter.report(\n installationId\n ? {config, message: config, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Report the exposes deploying with the application, both modes.\n const exposes = deployApplication && workbench ? reportExposes(reporter, workbench) : []\n\n // Surface the app's explicit singleton flag when set, both modes.\n if (deployApplication && workbench?.isSingleton !== undefined) {\n reporter.report({\n isSingleton: workbench.isSingleton,\n message: `Singleton: ${workbench.isSingleton}`,\n status: 'pass',\n })\n }\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(config ? {config} : {}),\n installationId,\n target: null,\n }\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n applicationId,\n icon: appIcon,\n interfaces: buildExposes(workbench, {\n appName: workbench.name,\n appTitle,\n exposesAppView: workbench.entry !== undefined,\n version,\n }),\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(exposes.length > 0 ? {exposes} : {}),\n ...(workbench.isSingleton === undefined ? {} : {isSingleton: workbench.isSingleton}),\n target: {\n action: applicationCreated ? 'create' : 'update',\n applicationId,\n // A redeploy targets an existing app; only a create reports the slug.\n ...(applicationCreated ? {slug: workbench.slug} : {}),\n title: appTitle,\n url,\n },\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n target: {\n action: appCreated ? 'create' : 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url: getCoreAppUrl(application.organizationId, application.id),\n },\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","exitCodes","getErrorMessage","getCoreAppUrl","spinner","buildExposes","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","summarizeConfig","pack","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportExposes","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","dryRun","deploySingletonConfig","deployApplication","hasInterfaces","appTitle","title","trim","name","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","isAutoUpdating","version","moduleName","application","appCreated","external","isWorkbenchApp","slug","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","rollback","isSingleton","visibility","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","config","configAppType","appType","exposes","deployApplicationConfig","applicationType","applicationVersion","target","interfaces","appName","exposesAppView","entry","onDeployed","url","id","logAppDeployed","length","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","entries","pipe","isApp","error","clear","named"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n summarizeConfig,\n} from '@sanity/workbench-cli/deploy'\nimport {pack} from 'tar-fs'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '../manifest/extractCoreAppManifest.js'\nimport {type CoreAppManifest} from '../manifest/types.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportExposes} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A singleton (the Media Library) persists its config instead of hosting an\n // application; anything that exposes a view or service still ships one.\n const deploySingletonConfig = workbench?.deploySingletonConfig ?? false\n const deployApplication = !workbench || workbench.hasInterfaces\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.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 const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deploySingletonConfig) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n ;({applicationId, rollback: rollbackApp} = await createCoreApp({\n isSingleton: workbench.isSingleton,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n }))\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({isWorkbenchApp: workbench !== null, reporter, sourceDir})\n\n // Workbench apps ship their icon straight to Brett (below) and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let config: string | undefined\n const configAppType = workbench?.config?.appType\n if (deploySingletonConfig && organizationId && workbench?.config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n config = summarizeConfig(workbench.config)\n reporter.report(\n installationId\n ? {config, message: config, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n // Report the exposes deploying with the application, both modes.\n const exposes = deployApplication && workbench ? reportExposes(reporter, workbench) : []\n\n // Surface the app's explicit singleton flag when set, both modes.\n if (deployApplication && workbench?.isSingleton !== undefined) {\n reporter.report({\n isSingleton: workbench.isSingleton,\n message: `Singleton: ${workbench.isSingleton}`,\n status: 'pass',\n })\n }\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(config ? {config} : {}),\n installationId,\n target: null,\n }\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n ...(exposes.length > 0 ? {exposes} : {}),\n ...(workbench.isSingleton === undefined ? {} : {isSingleton: workbench.isSingleton}),\n target: {\n action: applicationCreated ? 'create' : 'update',\n applicationId,\n // A redeploy targets an existing app; only a create reports the slug.\n ...(applicationCreated ? {slug: workbench.slug} : {}),\n title: appTitle,\n url,\n },\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n applicationType: 'coreApp',\n applicationVersion: version,\n target: {\n action: appCreated ? 'create' : 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url: getCoreAppUrl(application.organizationId, application.id),\n },\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","exitCodes","getErrorMessage","getCoreAppUrl","spinner","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","summarizeConfig","pack","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportExposes","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","dryRun","deploySingletonConfig","deployApplication","hasInterfaces","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","isAutoUpdating","version","moduleName","application","appCreated","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","rollback","isSingleton","visibility","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","config","configAppType","appType","exposes","deployApplicationConfig","applicationType","applicationVersion","target","isApp","onDeployed","url","id","logAppDeployed","length","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","entries","pipe","error","clear","named"],"mappings":"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"}
@@ -110,7 +110,7 @@ export async function checkBuild(reporter, { build, skipReason, successMessage }
110
110
  * The single diagnosis for each app deploy-target verdict, shared by the
111
111
  * dry-run report and the real deploy's unattended error paths so message,
112
112
  * fix, and exit code can't drift between the two.
113
- */ export function describeAppTarget(resolution, { slug, title } = {}) {
113
+ */ export function describeAppTarget(resolution, { title } = {}) {
114
114
  switch(resolution.type){
115
115
  case 'blocked':
116
116
  {
@@ -152,36 +152,23 @@ export async function checkBuild(reporter, { build, skipReason, successMessage }
152
152
  status: 'fail'
153
153
  };
154
154
  }
155
- // A deployment with no `appId` collides with an app already at this slug —
156
- // point at the existing app's id so a redeploy targets it instead of failing.
157
155
  case 'slug-taken':
158
156
  {
159
- const { existing: application } = resolution;
160
- return {
161
- exitCode: exitCodes.USAGE_ERROR,
162
- message: `An application already exists at slug "${application.appHost}" in this organization (app ID ${application.id})`,
163
- solution: `Add \`deployment: {appId: '${application.id}'}\` to sanity.cli.ts to redeploy it`,
164
- status: 'fail',
165
- target: {
166
- action: 'update',
167
- applicationId: application.id,
168
- title: application.title,
169
- url: application.url ?? null
170
- }
171
- };
157
+ return describeSlugTaken(resolution);
172
158
  }
173
159
  // Without --title, creating an app needs a prompt no unattended run can answer
174
160
  case 'would-create':
175
161
  {
162
+ const { appHost } = resolution;
176
163
  if (title) {
177
164
  return {
178
- message: `Would create a new application "${title}"${slug ? ` with slug "${slug}"` : ''}`,
165
+ message: `Would create a new application "${title}"${appHost ? ` with slug "${appHost}"` : ''}`,
179
166
  status: 'pass',
180
167
  target: {
181
168
  action: 'create',
182
169
  applicationId: null,
183
- ...slug ? {
184
- slug
170
+ ...appHost ? {
171
+ slug: appHost
185
172
  } : {},
186
173
  title,
187
174
  url: null
@@ -197,6 +184,20 @@ export async function checkBuild(reporter, { build, skipReason, successMessage }
197
184
  }
198
185
  }
199
186
  }
187
+ /** One diagnosis for both the app and studio verdicts: they share a slug namespace. */ function describeSlugTaken({ appHost, existing }) {
188
+ return {
189
+ exitCode: exitCodes.USAGE_ERROR,
190
+ message: `An application already exists at slug "${appHost}" in this organization (app ID ${existing.id})`,
191
+ solution: `Add \`deployment: {appId: '${existing.id}'}\` to sanity.cli.ts to redeploy it`,
192
+ status: 'fail',
193
+ target: {
194
+ action: 'update',
195
+ applicationId: existing.id,
196
+ title: existing.title,
197
+ url: existing.url ?? null
198
+ }
199
+ };
200
+ }
200
201
  export function describeAppTargetError(err, organizationId) {
201
202
  return err?.statusCode === 403 ? `You don’t have permission to view applications for the configured organization ID ("${organizationId}"). Verify the organization ID, or ask your organization’s admin for access.` : `Failed to resolve deploy target: ${getErrorMessage(err)}`;
202
203
  }
@@ -218,7 +219,6 @@ export function describeAppTargetError(err, organizationId) {
218
219
  slug
219
220
  });
220
221
  const check = describeAppTarget(resolution, {
221
- slug,
222
222
  title
223
223
  });
224
224
  reporter.report(check);
@@ -286,16 +286,16 @@ export function describeAppTargetError(err, organizationId) {
286
286
  status: 'fail'
287
287
  };
288
288
  }
289
+ case 'slug-taken':
290
+ {
291
+ return describeSlugTaken(resolution);
292
+ }
289
293
  case 'would-create':
290
294
  {
291
- // A workbench studio's URL needs the application id, which only exists after the create.
292
- const url = isWorkbench ? null : studioUrl(resolution.appHost);
293
- const titled = title ? ` titled "${title}"` : '';
294
- return {
295
- message: isExternal ? `Would register external studio at ${resolution.appHost}${titled}` : `Would create studio hostname ${url ?? resolution.appHost}${titled} (name availability is checked on deploy)`,
295
+ const appHost = resolution.appHost;
296
+ const url = isWorkbench ? null : studioUrl(appHost);
297
+ const result = {
296
298
  status: 'pass',
297
- // `title || null`, not `?? null`, so target.title tracks the same
298
- // truthiness the message's `titled` suffix uses (an empty title is no title)
299
299
  target: {
300
300
  action: 'create',
301
301
  applicationId: null,
@@ -303,6 +303,27 @@ export function describeAppTargetError(err, organizationId) {
303
303
  url
304
304
  }
305
305
  };
306
+ const titled = title ? ` titled "${title}"` : '';
307
+ if (isExternal) {
308
+ return {
309
+ message: `Would register external studio at ${appHost}${titled}`,
310
+ ...result
311
+ };
312
+ }
313
+ if (isWorkbench) {
314
+ return {
315
+ message: `Would create a new studio${title ? ` "${title}"` : ''} with slug "${appHost}" (name availability is checked on deploy)`,
316
+ ...result,
317
+ target: {
318
+ ...result.target,
319
+ slug: appHost
320
+ }
321
+ };
322
+ }
323
+ return {
324
+ message: `Would create studio hostname ${url}${titled} (name availability is checked on deploy)`,
325
+ ...result
326
+ };
306
327
  }
307
328
  }
308
329
  }
@@ -312,10 +333,7 @@ export function describeAppTargetError(err, organizationId) {
312
333
  * it to reject a bad `appId` before building.
313
334
  */ export async function checkStudioTarget(reporter, options) {
314
335
  const { title } = options;
315
- const resolve = options.isWorkbenchApp ? resolveWorkbenchStudio({
316
- appId: options.appId,
317
- slug: options.slug
318
- }) : resolveStudioDeployTarget(options);
336
+ const resolve = options.isWorkbenchApp ? resolveWorkbenchStudio(options) : resolveStudioDeployTarget(options);
319
337
  // Workbench studios always deploy to Sanity hosting, never an external URL.
320
338
  const isExternal = options.isWorkbenchApp ? false : options.isExternal;
321
339
  return runStep(reporter, {