@sanity/cli 7.7.1 → 7.9.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 (82) hide show
  1. package/README.md +17 -2
  2. package/dist/actions/auth/ensureAuthenticated.js +1 -1
  3. package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
  4. package/dist/actions/auth/login/validateToken.js +1 -1
  5. package/dist/actions/auth/login/validateToken.js.map +1 -1
  6. package/dist/actions/build/buildApp.js +2 -3
  7. package/dist/actions/build/buildApp.js.map +1 -1
  8. package/dist/actions/build/buildStudio.js +1 -2
  9. package/dist/actions/build/buildStudio.js.map +1 -1
  10. package/dist/actions/deploy/createUserApplication.js +8 -8
  11. package/dist/actions/deploy/createUserApplication.js.map +1 -1
  12. package/dist/actions/deploy/deployApp.js +128 -26
  13. package/dist/actions/deploy/deployApp.js.map +1 -1
  14. package/dist/actions/deploy/deployChecks.js +97 -72
  15. package/dist/actions/deploy/deployChecks.js.map +1 -1
  16. package/dist/actions/deploy/deployRunner.js +8 -8
  17. package/dist/actions/deploy/deployRunner.js.map +1 -1
  18. package/dist/actions/deploy/deployStudio.js +129 -23
  19. package/dist/actions/deploy/deployStudio.js.map +1 -1
  20. package/dist/actions/deploy/deploymentPlan.js +29 -30
  21. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  22. package/dist/actions/deploy/findUserApplication.js +39 -14
  23. package/dist/actions/deploy/findUserApplication.js.map +1 -1
  24. package/dist/actions/deploy/resolveDeployTarget.js +44 -0
  25. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  26. package/dist/actions/deploy/urlUtils.js +0 -4
  27. package/dist/actions/deploy/urlUtils.js.map +1 -1
  28. package/dist/actions/dev/servers/getDevServerConfig.js +1 -1
  29. package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
  30. package/dist/actions/dev/servers/startStudioDevServer.js +1 -2
  31. package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
  32. package/dist/actions/documents/types.js.map +1 -1
  33. package/dist/actions/documents/validate.js +2 -1
  34. package/dist/actions/documents/validate.js.map +1 -1
  35. package/dist/actions/graphql/SchemaError.js.map +1 -1
  36. package/dist/actions/graphql/extractGraphQLAPIs.js +3 -1
  37. package/dist/actions/graphql/extractGraphQLAPIs.js.map +1 -1
  38. package/dist/actions/manifest/extractCoreAppManifest.js +1 -1
  39. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  40. package/dist/actions/organizations/getOrganization.js +1 -1
  41. package/dist/actions/organizations/getOrganization.js.map +1 -1
  42. package/dist/actions/schema/validateAction.js +1 -1
  43. package/dist/actions/schema/validateAction.js.map +1 -1
  44. package/dist/actions/skills/setupSkills.js +1 -1
  45. package/dist/actions/skills/setupSkills.js.map +1 -1
  46. package/dist/actions/undeploy/adapters.js +101 -0
  47. package/dist/actions/undeploy/adapters.js.map +1 -0
  48. package/dist/actions/undeploy/runUndeploy.js +179 -0
  49. package/dist/actions/undeploy/runUndeploy.js.map +1 -0
  50. package/dist/actions/undeploy/undeployPlan.js +123 -0
  51. package/dist/actions/undeploy/undeployPlan.js.map +1 -0
  52. package/dist/commands/datasets/copy.js +2 -1
  53. package/dist/commands/datasets/copy.js.map +1 -1
  54. package/dist/commands/documents/validate.js +18 -17
  55. package/dist/commands/documents/validate.js.map +1 -1
  56. package/dist/commands/mcp/configure.js +1 -1
  57. package/dist/commands/mcp/configure.js.map +1 -1
  58. package/dist/commands/projects/create.js +18 -13
  59. package/dist/commands/projects/create.js.map +1 -1
  60. package/dist/commands/projects/list.js +2 -1
  61. package/dist/commands/projects/list.js.map +1 -1
  62. package/dist/commands/schemas/validate.js +3 -2
  63. package/dist/commands/schemas/validate.js.map +1 -1
  64. package/dist/commands/skills/install.js +1 -1
  65. package/dist/commands/skills/install.js.map +1 -1
  66. package/dist/commands/tokens/list.js +1 -1
  67. package/dist/commands/tokens/list.js.map +1 -1
  68. package/dist/commands/undeploy.js +47 -73
  69. package/dist/commands/undeploy.js.map +1 -1
  70. package/dist/server/devServer.js.map +1 -1
  71. package/dist/util/checks.js +83 -0
  72. package/dist/util/checks.js.map +1 -0
  73. package/dist/util/toStderrOutput.js +13 -0
  74. package/dist/util/toStderrOutput.js.map +1 -0
  75. package/oclif.manifest.json +28 -1
  76. package/package.json +7 -8
  77. package/dist/actions/undeploy/getStudioOrAppUserApplication.js +0 -36
  78. package/dist/actions/undeploy/getStudioOrAppUserApplication.js.map +0 -1
  79. package/dist/util/compareDependencyVersions.js +0 -110
  80. package/dist/util/compareDependencyVersions.js.map +0 -1
  81. package/dist/util/getErrorMessage.js +0 -28
  82. package/dist/util/getErrorMessage.js.map +0 -1
package/README.md CHANGED
@@ -3427,13 +3427,28 @@ Removes the deployed Sanity Studio/App from Sanity hosting
3427
3427
 
3428
3428
  ```
3429
3429
  USAGE
3430
- $ sanity undeploy [-y]
3430
+ $ sanity undeploy [--dry-run] [-j] [-y]
3431
3431
 
3432
3432
  FLAGS
3433
- -y, --yes Unattended mode, answers "yes" to any "yes/no" prompt and otherwise uses defaults
3433
+ -j, --json Output the result as JSON
3434
+ -y, --yes Unattended mode, answers "yes" to any "yes/no" prompt and otherwise uses defaults
3435
+ --dry-run Report what would be undeployed without deleting anything
3434
3436
 
3435
3437
  DESCRIPTION
3436
3438
  Removes the deployed Sanity Studio/App from Sanity hosting
3439
+
3440
+ EXAMPLES
3441
+ Undeploy the studio or application after confirming
3442
+
3443
+ $ sanity undeploy
3444
+
3445
+ Report what would be undeployed without deleting anything
3446
+
3447
+ $ sanity undeploy --dry-run
3448
+
3449
+ Undeploy without prompting and report the result as JSON
3450
+
3451
+ $ sanity undeploy --json --yes
3437
3452
  ```
3438
3453
 
3439
3454
  ## `sanity users invite [EMAIL]`
@@ -1,8 +1,8 @@
1
1
  import { getCliToken } from '@sanity/cli-core';
2
+ import { getErrorMessage } from '@sanity/cli-core/errors';
2
3
  import { isHttpError } from '@sanity/client';
3
4
  import { LoginError } from '../../errors/LoginError.js';
4
5
  import { getCliUser } from '../../services/user.js';
5
- import { getErrorMessage } from '../../util/getErrorMessage.js';
6
6
  import { login } from './login/login.js';
7
7
  /**
8
8
  * Ensure the user is authenticated. Validates the current token via /users/me
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/auth/ensureAuthenticated.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n type Output,\n type SanityOrgUser,\n} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {LoginError} from '../../errors/LoginError.js'\nimport {getCliUser} from '../../services/user.js'\nimport {getErrorMessage} from '../../util/getErrorMessage.js'\nimport {login} from './login/login.js'\n\n/**\n * Ensure the user is authenticated. Validates the current token via /users/me\n * and triggers interactive login if the token is missing or invalid.\n *\n * @returns The authenticated user.\n * @throws LoginError if interactive login fails or is cancelled.\n * @throws Error if a network/server error occurs during validation.\n * @internal\n */\nexport async function ensureAuthenticated(options: {\n output: Output\n telemetry: CLITelemetryStore\n}): Promise<SanityOrgUser> {\n const user = await validateSession()\n if (user) return user\n\n try {\n await login({output: options.output, telemetry: options.telemetry})\n } catch (cause) {\n throw new LoginError(getErrorMessage(cause), {cause})\n }\n\n try {\n return await getCliUser()\n } catch (cause) {\n if (isHttpError(cause) && (cause.statusCode === 401 || cause.statusCode === 403)) {\n throw new LoginError(\n `Login succeeded but failed to verify session: ${getErrorMessage(cause)}`,\n {cause},\n )\n }\n throw cause\n }\n}\n\n/**\n * Validate the current CLI auth token by calling /users/me.\n *\n * Returns null only for auth failures (401/403). Re-throws network errors,\n * timeouts, and server errors so callers can handle them appropriately\n * instead of triggering an unnecessary re-login prompt.\n *\n * @returns The authenticated user if valid, null if invalid/missing.\n * @internal\n */\nexport async function validateSession(): Promise<SanityOrgUser | null> {\n const token = await getCliToken()\n if (!token) return null\n\n try {\n return await getCliUser()\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n return null\n }\n throw error\n }\n}\n"],"names":["getCliToken","isHttpError","LoginError","getCliUser","getErrorMessage","login","ensureAuthenticated","options","user","validateSession","output","telemetry","cause","statusCode","token","error"],"mappings":"AAAA,SAEEA,WAAW,QAGN,mBAAkB;AACzB,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,UAAU,QAAO,yBAAwB;AACjD,SAAQC,eAAe,QAAO,gCAA+B;AAC7D,SAAQC,KAAK,QAAO,mBAAkB;AAEtC;;;;;;;;CAQC,GACD,OAAO,eAAeC,oBAAoBC,OAGzC;IACC,MAAMC,OAAO,MAAMC;IACnB,IAAID,MAAM,OAAOA;IAEjB,IAAI;QACF,MAAMH,MAAM;YAACK,QAAQH,QAAQG,MAAM;YAAEC,WAAWJ,QAAQI,SAAS;QAAA;IACnE,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIV,WAAWE,gBAAgBQ,QAAQ;YAACA;QAAK;IACrD;IAEA,IAAI;QACF,OAAO,MAAMT;IACf,EAAE,OAAOS,OAAO;QACd,IAAIX,YAAYW,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIX,WACR,CAAC,8CAA8C,EAAEE,gBAAgBQ,QAAQ,EACzE;gBAACA;YAAK;QAEV;QACA,MAAMA;IACR;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,eAAeH;IACpB,MAAMK,QAAQ,MAAMd;IACpB,IAAI,CAACc,OAAO,OAAO;IAEnB,IAAI;QACF,OAAO,MAAMX;IACf,EAAE,OAAOY,OAAO;QACd,IAAId,YAAYc,UAAWA,CAAAA,MAAMF,UAAU,KAAK,OAAOE,MAAMF,UAAU,KAAK,GAAE,GAAI;YAChF,OAAO;QACT;QACA,MAAME;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/auth/ensureAuthenticated.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n type Output,\n type SanityOrgUser,\n} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {LoginError} from '../../errors/LoginError.js'\nimport {getCliUser} from '../../services/user.js'\nimport {login} from './login/login.js'\n\n/**\n * Ensure the user is authenticated. Validates the current token via /users/me\n * and triggers interactive login if the token is missing or invalid.\n *\n * @returns The authenticated user.\n * @throws LoginError if interactive login fails or is cancelled.\n * @throws Error if a network/server error occurs during validation.\n * @internal\n */\nexport async function ensureAuthenticated(options: {\n output: Output\n telemetry: CLITelemetryStore\n}): Promise<SanityOrgUser> {\n const user = await validateSession()\n if (user) return user\n\n try {\n await login({output: options.output, telemetry: options.telemetry})\n } catch (cause) {\n throw new LoginError(getErrorMessage(cause), {cause})\n }\n\n try {\n return await getCliUser()\n } catch (cause) {\n if (isHttpError(cause) && (cause.statusCode === 401 || cause.statusCode === 403)) {\n throw new LoginError(\n `Login succeeded but failed to verify session: ${getErrorMessage(cause)}`,\n {cause},\n )\n }\n throw cause\n }\n}\n\n/**\n * Validate the current CLI auth token by calling /users/me.\n *\n * Returns null only for auth failures (401/403). Re-throws network errors,\n * timeouts, and server errors so callers can handle them appropriately\n * instead of triggering an unnecessary re-login prompt.\n *\n * @returns The authenticated user if valid, null if invalid/missing.\n * @internal\n */\nexport async function validateSession(): Promise<SanityOrgUser | null> {\n const token = await getCliToken()\n if (!token) return null\n\n try {\n return await getCliUser()\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n return null\n }\n throw error\n }\n}\n"],"names":["getCliToken","getErrorMessage","isHttpError","LoginError","getCliUser","login","ensureAuthenticated","options","user","validateSession","output","telemetry","cause","statusCode","token","error"],"mappings":"AAAA,SAEEA,WAAW,QAGN,mBAAkB;AACzB,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,UAAU,QAAO,yBAAwB;AACjD,SAAQC,KAAK,QAAO,mBAAkB;AAEtC;;;;;;;;CAQC,GACD,OAAO,eAAeC,oBAAoBC,OAGzC;IACC,MAAMC,OAAO,MAAMC;IACnB,IAAID,MAAM,OAAOA;IAEjB,IAAI;QACF,MAAMH,MAAM;YAACK,QAAQH,QAAQG,MAAM;YAAEC,WAAWJ,QAAQI,SAAS;QAAA;IACnE,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIT,WAAWF,gBAAgBW,QAAQ;YAACA;QAAK;IACrD;IAEA,IAAI;QACF,OAAO,MAAMR;IACf,EAAE,OAAOQ,OAAO;QACd,IAAIV,YAAYU,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIV,WACR,CAAC,8CAA8C,EAAEF,gBAAgBW,QAAQ,EACzE;gBAACA;YAAK;QAEV;QACA,MAAMA;IACR;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,eAAeH;IACpB,MAAMK,QAAQ,MAAMd;IACpB,IAAI,CAACc,OAAO,OAAO;IAEnB,IAAI;QACF,OAAO,MAAMV;IACf,EAAE,OAAOW,OAAO;QACd,IAAIb,YAAYa,UAAWA,CAAAA,MAAMF,UAAU,KAAK,OAAOE,MAAMF,UAAU,KAAK,GAAE,GAAI;YAChF,OAAO;QACT;QACA,MAAME;IACR;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { getGlobalCliClient } from '@sanity/cli-core';
2
+ import { getErrorMessage } from '@sanity/cli-core/errors';
2
3
  import { isHttpError } from '@sanity/client';
3
4
  import { USERS_API_VERSION } from '../../../services/user.js';
4
- import { getErrorMessage } from '../../../util/getErrorMessage.js';
5
5
  export async function validateToken(token) {
6
6
  const trimmedToken = token.trim();
7
7
  if (!trimmedToken) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/actions/auth/login/validateToken.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {USERS_API_VERSION} from '../../../services/user.js'\nimport {getErrorMessage} from '../../../util/getErrorMessage.js'\n\nexport async function validateToken(token: string): Promise<string> {\n const trimmedToken = token.trim()\n\n if (!trimmedToken) {\n throw new Error(\n 'Token is required on standard input. Run `sanity login --with-token < token.txt`.',\n )\n }\n\n try {\n await getTokenUser(trimmedToken)\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n throw new Error('Token is invalid or expired. Check the token and try again.', {cause: error})\n }\n\n throw new Error(`Could not verify token: ${getErrorMessage(error)}`, {cause: error})\n }\n\n return trimmedToken\n}\n\nexport async function isSanityApiToken(token: string): Promise<boolean> {\n return isSanityApiTokenUser(await getTokenUser(token))\n}\n\nasync function getTokenUser(token: string): Promise<unknown> {\n const client = await getGlobalCliClient({\n apiVersion: USERS_API_VERSION,\n requireUser: true,\n token,\n })\n\n return client.users.getById('me')\n}\n\nfunction isSanityApiTokenUser(user: unknown): boolean {\n return (\n typeof user === 'object' &&\n user !== null &&\n 'provider' in user &&\n (user as {provider?: unknown}).provider === 'sanity-token'\n )\n}\n"],"names":["getGlobalCliClient","isHttpError","USERS_API_VERSION","getErrorMessage","validateToken","token","trimmedToken","trim","Error","getTokenUser","error","statusCode","cause","isSanityApiToken","isSanityApiTokenUser","client","apiVersion","requireUser","users","getById","user","provider"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AACnD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,iBAAiB,QAAO,4BAA2B;AAC3D,SAAQC,eAAe,QAAO,mCAAkC;AAEhE,OAAO,eAAeC,cAAcC,KAAa;IAC/C,MAAMC,eAAeD,MAAME,IAAI;IAE/B,IAAI,CAACD,cAAc;QACjB,MAAM,IAAIE,MACR;IAEJ;IAEA,IAAI;QACF,MAAMC,aAAaH;IACrB,EAAE,OAAOI,OAAO;QACd,IAAIT,YAAYS,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIH,MAAM,+DAA+D;gBAACI,OAAOF;YAAK;QAC9F;QAEA,MAAM,IAAIF,MAAM,CAAC,wBAAwB,EAAEL,gBAAgBO,QAAQ,EAAE;YAACE,OAAOF;QAAK;IACpF;IAEA,OAAOJ;AACT;AAEA,OAAO,eAAeO,iBAAiBR,KAAa;IAClD,OAAOS,qBAAqB,MAAML,aAAaJ;AACjD;AAEA,eAAeI,aAAaJ,KAAa;IACvC,MAAMU,SAAS,MAAMf,mBAAmB;QACtCgB,YAAYd;QACZe,aAAa;QACbZ;IACF;IAEA,OAAOU,OAAOG,KAAK,CAACC,OAAO,CAAC;AAC9B;AAEA,SAASL,qBAAqBM,IAAa;IACzC,OACE,OAAOA,SAAS,YAChBA,SAAS,QACT,cAAcA,QACd,AAACA,KAA8BC,QAAQ,KAAK;AAEhD"}
1
+ {"version":3,"sources":["../../../../src/actions/auth/login/validateToken.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {USERS_API_VERSION} from '../../../services/user.js'\n\nexport async function validateToken(token: string): Promise<string> {\n const trimmedToken = token.trim()\n\n if (!trimmedToken) {\n throw new Error(\n 'Token is required on standard input. Run `sanity login --with-token < token.txt`.',\n )\n }\n\n try {\n await getTokenUser(trimmedToken)\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n throw new Error('Token is invalid or expired. Check the token and try again.', {cause: error})\n }\n\n throw new Error(`Could not verify token: ${getErrorMessage(error)}`, {cause: error})\n }\n\n return trimmedToken\n}\n\nexport async function isSanityApiToken(token: string): Promise<boolean> {\n return isSanityApiTokenUser(await getTokenUser(token))\n}\n\nasync function getTokenUser(token: string): Promise<unknown> {\n const client = await getGlobalCliClient({\n apiVersion: USERS_API_VERSION,\n requireUser: true,\n token,\n })\n\n return client.users.getById('me')\n}\n\nfunction isSanityApiTokenUser(user: unknown): boolean {\n return (\n typeof user === 'object' &&\n user !== null &&\n 'provider' in user &&\n (user as {provider?: unknown}).provider === 'sanity-token'\n )\n}\n"],"names":["getGlobalCliClient","getErrorMessage","isHttpError","USERS_API_VERSION","validateToken","token","trimmedToken","trim","Error","getTokenUser","error","statusCode","cause","isSanityApiToken","isSanityApiTokenUser","client","apiVersion","requireUser","users","getById","user","provider"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AACnD,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,iBAAiB,QAAO,4BAA2B;AAE3D,OAAO,eAAeC,cAAcC,KAAa;IAC/C,MAAMC,eAAeD,MAAME,IAAI;IAE/B,IAAI,CAACD,cAAc;QACjB,MAAM,IAAIE,MACR;IAEJ;IAEA,IAAI;QACF,MAAMC,aAAaH;IACrB,EAAE,OAAOI,OAAO;QACd,IAAIR,YAAYQ,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIH,MAAM,+DAA+D;gBAACI,OAAOF;YAAK;QAC9F;QAEA,MAAM,IAAIF,MAAM,CAAC,wBAAwB,EAAEP,gBAAgBS,QAAQ,EAAE;YAACE,OAAOF;QAAK;IACpF;IAEA,OAAOJ;AACT;AAEA,OAAO,eAAeO,iBAAiBR,KAAa;IAClD,OAAOS,qBAAqB,MAAML,aAAaJ;AACjD;AAEA,eAAeI,aAAaJ,KAAa;IACvC,MAAMU,SAAS,MAAMf,mBAAmB;QACtCgB,YAAYb;QACZc,aAAa;QACbZ;IACF;IAEA,OAAOU,OAAOG,KAAK,CAACC,OAAO,CAAC;AAC9B;AAEA,SAASL,qBAAqBM,IAAa;IACzC,OACE,OAAOA,SAAS,YAChBA,SAAS,QACT,cAAcA,QACd,AAACA,KAA8BC,QAAQ,KAAK;AAEhD"}
@@ -1,7 +1,6 @@
1
- import { buildApp as internalBuildApp } from '@sanity/cli-build/_internal/build';
1
+ import { compareDependencyVersions, buildApp as internalBuildApp } from '@sanity/cli-build/_internal/build';
2
2
  import { resolveWorkbenchApp } from '@sanity/workbench-cli/build';
3
3
  import { getAppId } from '../../util/appId.js';
4
- import { compareDependencyVersions } from '../../util/compareDependencyVersions.js';
5
4
  import { warnAboutMissingAppId } from '../../util/warnAboutMissingAppId.js';
6
5
  import { determineBasePath } from './determineBasePath.js';
7
6
  /**
@@ -36,7 +35,7 @@ import { determineBasePath } from './determineBasePath.js';
36
35
  determineBasePath: ()=>determineBasePath(cliConfig, 'app', output),
37
36
  entry: app?.entry,
38
37
  exposes: workbench ? {
39
- installationConfig: workbench.installationConfig,
38
+ config: workbench.config,
40
39
  services: workbench.services,
41
40
  views: workbench.views
42
41
  } : undefined,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/buildApp.ts"],"sourcesContent":["import {buildApp as internalBuildApp} from '@sanity/cli-build/_internal/build'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\n\nimport {getAppId} from '../../util/appId.js'\nimport {compareDependencyVersions} from '../../util/compareDependencyVersions.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity app.\n *\n * @internal\n */\nexport async function buildApp(options: BuildOptions): Promise<void> {\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const app = cliConfig && 'app' in cliConfig ? cliConfig.app : undefined\n // `views`/`services` live on the branded `unstable_defineApp` result, not the\n // legacy `app` config object — resolve the workbench capability to read them.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n await internalBuildApp({\n appId,\n appTitle: app?.title,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !options.calledFromDeploy) {\n warnAboutMissingAppId({appType: 'app', output})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'app', output),\n entry: app?.entry,\n exposes: workbench\n ? {\n installationConfig: workbench.installationConfig,\n services: workbench.services,\n views: workbench.views,\n }\n : undefined,\n isWorkbenchApp: !!workbench,\n minify: flags.minify,\n outDir,\n output,\n reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n schemaExtraction: cliConfig?.schemaExtraction,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: flags.yes,\n vite: cliConfig.vite,\n workbenchAppId: workbench?.name,\n workDir,\n })\n}\n"],"names":["buildApp","internalBuildApp","resolveWorkbenchApp","getAppId","compareDependencyVersions","warnAboutMissingAppId","determineBasePath","options","cliConfig","flags","outDir","output","workDir","app","undefined","workbench","appId","appTitle","title","autoUpdatesEnabled","checkAppId","calledFromDeploy","appType","packages","entry","exposes","installationConfig","services","views","isWorkbenchApp","minify","reactCompiler","schemaExtraction","sourceMap","Boolean","stats","unattendedMode","yes","vite","workbenchAppId","name"],"mappings":"AAAA,SAAQA,YAAYC,gBAAgB,QAAO,oCAAmC;AAC9E,SAAQC,mBAAmB,QAAO,8BAA6B;AAE/D,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,yBAAyB,QAAO,0CAAyC;AACjF,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AAGxD;;;;CAIC,GACD,OAAO,eAAeN,SAASO,OAAqB;IAClD,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAEpD,MAAMM,MAAML,aAAa,SAASA,YAAYA,UAAUK,GAAG,GAAGC;IAC9D,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAMC,YAAYb,oBAAoBM;IAEtC,MAAMQ,QAAQb,SAASK;IAEvB,MAAMP,iBAAiB;QACrBe;QACAC,UAAUJ,KAAKK;QACfC,oBAAoBZ,QAAQY,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACJ,SAAS,CAACT,QAAQc,gBAAgB,EAAE;gBACvChB,sBAAsB;oBAACiB,SAAS;oBAAOX;gBAAM;YAC/C;QACF;QACAP,2BAA2B,CAACmB,WAAanB,0BAA0BmB,UAAUX,SAAS;gBAACI;YAAK;QAC5FV,mBAAmB,IAAMA,kBAAkBE,WAAW,OAAOG;QAC7Da,OAAOX,KAAKW;QACZC,SAASV,YACL;YACEW,oBAAoBX,UAAUW,kBAAkB;YAChDC,UAAUZ,UAAUY,QAAQ;YAC5BC,OAAOb,UAAUa,KAAK;QACxB,IACAd;QACJe,gBAAgB,CAAC,CAACd;QAClBe,QAAQrB,MAAMqB,MAAM;QACpBpB;QACAC;QACAoB,eAAevB,aAAa,mBAAmBA,YAAYA,UAAUuB,aAAa,GAAGjB;QACrFkB,kBAAkBxB,WAAWwB;QAC7BC,WAAWC,QAAQzB,KAAK,CAAC,cAAc;QACvC0B,OAAO1B,MAAM0B,KAAK;QAClBC,gBAAgB3B,MAAM4B,GAAG;QACzBC,MAAM9B,UAAU8B,IAAI;QACpBC,gBAAgBxB,WAAWyB;QAC3B5B;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/build/buildApp.ts"],"sourcesContent":["import {\n compareDependencyVersions,\n buildApp as internalBuildApp,\n} from '@sanity/cli-build/_internal/build'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\n\nimport {getAppId} from '../../util/appId.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity app.\n *\n * @internal\n */\nexport async function buildApp(options: BuildOptions): Promise<void> {\n const {cliConfig, flags, outDir, output, workDir} = options\n\n const app = cliConfig && 'app' in cliConfig ? cliConfig.app : undefined\n // `views`/`services` live on the branded `unstable_defineApp` result, not the\n // legacy `app` config object — resolve the workbench capability to read them.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n await internalBuildApp({\n appId,\n appTitle: app?.title,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !options.calledFromDeploy) {\n warnAboutMissingAppId({appType: 'app', output})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'app', output),\n entry: app?.entry,\n exposes: workbench\n ? {\n config: workbench.config,\n services: workbench.services,\n views: workbench.views,\n }\n : undefined,\n isWorkbenchApp: !!workbench,\n minify: flags.minify,\n outDir,\n output,\n reactCompiler: cliConfig && 'reactCompiler' in cliConfig ? cliConfig.reactCompiler : undefined,\n schemaExtraction: cliConfig?.schemaExtraction,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: flags.yes,\n vite: cliConfig.vite,\n workbenchAppId: workbench?.name,\n workDir,\n })\n}\n"],"names":["compareDependencyVersions","buildApp","internalBuildApp","resolveWorkbenchApp","getAppId","warnAboutMissingAppId","determineBasePath","options","cliConfig","flags","outDir","output","workDir","app","undefined","workbench","appId","appTitle","title","autoUpdatesEnabled","checkAppId","calledFromDeploy","appType","packages","entry","exposes","config","services","views","isWorkbenchApp","minify","reactCompiler","schemaExtraction","sourceMap","Boolean","stats","unattendedMode","yes","vite","workbenchAppId","name"],"mappings":"AAAA,SACEA,yBAAyB,EACzBC,YAAYC,gBAAgB,QACvB,oCAAmC;AAC1C,SAAQC,mBAAmB,QAAO,8BAA6B;AAE/D,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AAGxD;;;;CAIC,GACD,OAAO,eAAeL,SAASM,OAAqB;IAClD,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGL;IAEpD,MAAMM,MAAML,aAAa,SAASA,YAAYA,UAAUK,GAAG,GAAGC;IAC9D,8EAA8E;IAC9E,8EAA8E;IAC9E,MAAMC,YAAYZ,oBAAoBK;IAEtC,MAAMQ,QAAQZ,SAASI;IAEvB,MAAMN,iBAAiB;QACrBc;QACAC,UAAUJ,KAAKK;QACfC,oBAAoBZ,QAAQY,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACJ,SAAS,CAACT,QAAQc,gBAAgB,EAAE;gBACvChB,sBAAsB;oBAACiB,SAAS;oBAAOX;gBAAM;YAC/C;QACF;QACAX,2BAA2B,CAACuB,WAAavB,0BAA0BuB,UAAUX,SAAS;gBAACI;YAAK;QAC5FV,mBAAmB,IAAMA,kBAAkBE,WAAW,OAAOG;QAC7Da,OAAOX,KAAKW;QACZC,SAASV,YACL;YACEW,QAAQX,UAAUW,MAAM;YACxBC,UAAUZ,UAAUY,QAAQ;YAC5BC,OAAOb,UAAUa,KAAK;QACxB,IACAd;QACJe,gBAAgB,CAAC,CAACd;QAClBe,QAAQrB,MAAMqB,MAAM;QACpBpB;QACAC;QACAoB,eAAevB,aAAa,mBAAmBA,YAAYA,UAAUuB,aAAa,GAAGjB;QACrFkB,kBAAkBxB,WAAWwB;QAC7BC,WAAWC,QAAQzB,KAAK,CAAC,cAAc;QACvC0B,OAAO1B,MAAM0B,KAAK;QAClBC,gBAAgB3B,MAAM4B,GAAG;QACzBC,MAAM9B,UAAU8B,IAAI;QACpBC,gBAAgBxB,WAAWyB;QAC3B5B;IACF;AACF"}
@@ -1,7 +1,6 @@
1
- import { buildStudio as internalBuildStudio } from '@sanity/cli-build/_internal/build';
1
+ import { compareDependencyVersions, buildStudio as internalBuildStudio } from '@sanity/cli-build/_internal/build';
2
2
  import { resolveWorkbenchApp } from '@sanity/workbench-cli/build';
3
3
  import { getAppId } from '../../util/appId.js';
4
- import { compareDependencyVersions } from '../../util/compareDependencyVersions.js';
5
4
  import { determineIsApp } from '../../util/determineIsApp.js';
6
5
  import { getPackageManagerChoice } from '../../util/packageManager/packageManagerChoice.js';
7
6
  import { upgradePackages } from '../../util/packageManager/upgradePackages.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/buildStudio.ts"],"sourcesContent":["import {buildStudio as internalBuildStudio} from '@sanity/cli-build/_internal/build'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\n\nimport {getAppId} from '../../util/appId.js'\nimport {compareDependencyVersions} from '../../util/compareDependencyVersions.js'\nimport {determineIsApp} from '../../util/determineIsApp.js'\nimport {getPackageManagerChoice} from '../../util/packageManager/packageManagerChoice.js'\nimport {upgradePackages} from '../../util/packageManager/upgradePackages.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const {calledFromDeploy, cliConfig, flags, outDir, output, workDir} = options\n\n // `views`/`services` live on the branded `unstable_defineApp` result — resolve\n // the workbench capability so it's gated on the brand, like the app build.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n const upgradePkgs = async (options: {\n packages: [name: string, version: string][]\n }): Promise<void> => {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: options.packages,\n },\n {output, workDir},\n )\n }\n\n await internalBuildStudio({\n appId,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId: cliConfig?.api?.projectId})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'studio', output),\n exposes: workbench ? {services: workbench.services, views: workbench.views} : undefined,\n isApp: determineIsApp(cliConfig),\n isWorkbenchApp: !!workbench,\n minify: Boolean(flags.minify),\n outDir,\n output,\n reactCompiler: cliConfig.reactCompiler,\n schemaExtraction: cliConfig.schemaExtraction,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: Boolean(flags.yes),\n upgradePackages: upgradePkgs,\n vite: cliConfig.vite,\n workbenchAppId: workbench?.name,\n workDir,\n })\n}\n"],"names":["buildStudio","internalBuildStudio","resolveWorkbenchApp","getAppId","compareDependencyVersions","determineIsApp","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","determineBasePath","options","calledFromDeploy","cliConfig","flags","outDir","output","workDir","workbench","appId","upgradePkgs","packageManager","interactive","chosen","packages","autoUpdatesEnabled","checkAppId","appType","projectId","api","exposes","services","views","undefined","isApp","isWorkbenchApp","minify","Boolean","reactCompiler","schemaExtraction","sourceMap","stats","unattendedMode","yes","vite","workbenchAppId","name"],"mappings":"AAAA,SAAQA,eAAeC,mBAAmB,QAAO,oCAAmC;AACpF,SAAQC,mBAAmB,QAAO,8BAA6B;AAE/D,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,yBAAyB,QAAO,0CAAyC;AACjF,SAAQC,cAAc,QAAO,+BAA8B;AAC3D,SAAQC,uBAAuB,QAAO,oDAAmD;AACzF,SAAQC,eAAe,QAAO,+CAA8C;AAC5E,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AAGxD;;;;CAIC,GACD,OAAO,eAAeT,YAAYU,OAAqB;IACrD,MAAM,EAACC,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGN;IAEtE,+EAA+E;IAC/E,2EAA2E;IAC3E,MAAMO,YAAYf,oBAAoBU;IAEtC,MAAMM,QAAQf,SAASS;IAEvB,MAAMO,cAAc,OAAOT;QAGzB,MAAMH,gBACJ;YACEa,gBAAgB,AAAC,CAAA,MAAMd,wBAAwBU,SAAS;gBAACK,aAAa;YAAK,EAAC,EAAGC,MAAM;YACrFC,UAAUb,QAAQa,QAAQ;QAC5B,GACA;YAACR;YAAQC;QAAO;IAEpB;IAEA,MAAMf,oBAAoB;QACxBiB;QACAM,oBAAoBd,QAAQc,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACP,SAAS,CAACP,kBAAkB;gBAC/BH,sBAAsB;oBAACkB,SAAS;oBAAUX;oBAAQY,WAAWf,WAAWgB,KAAKD;gBAAS;YACxF;QACF;QACAvB,2BAA2B,CAACmB,WAAanB,0BAA0BmB,UAAUP,SAAS;gBAACE;YAAK;QAC5FT,mBAAmB,IAAMA,kBAAkBG,WAAW,UAAUG;QAChEc,SAASZ,YAAY;YAACa,UAAUb,UAAUa,QAAQ;YAAEC,OAAOd,UAAUc,KAAK;QAAA,IAAIC;QAC9EC,OAAO5B,eAAeO;QACtBsB,gBAAgB,CAAC,CAACjB;QAClBkB,QAAQC,QAAQvB,MAAMsB,MAAM;QAC5BrB;QACAC;QACAsB,eAAezB,UAAUyB,aAAa;QACtCC,kBAAkB1B,UAAU0B,gBAAgB;QAC5CC,WAAWH,QAAQvB,KAAK,CAAC,cAAc;QACvC2B,OAAO3B,MAAM2B,KAAK;QAClBC,gBAAgBL,QAAQvB,MAAM6B,GAAG;QACjCnC,iBAAiBY;QACjBwB,MAAM/B,UAAU+B,IAAI;QACpBC,gBAAgB3B,WAAW4B;QAC3B7B;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/build/buildStudio.ts"],"sourcesContent":["import {\n compareDependencyVersions,\n buildStudio as internalBuildStudio,\n} from '@sanity/cli-build/_internal/build'\nimport {resolveWorkbenchApp} from '@sanity/workbench-cli/build'\n\nimport {getAppId} from '../../util/appId.js'\nimport {determineIsApp} from '../../util/determineIsApp.js'\nimport {getPackageManagerChoice} from '../../util/packageManager/packageManagerChoice.js'\nimport {upgradePackages} from '../../util/packageManager/upgradePackages.js'\nimport {warnAboutMissingAppId} from '../../util/warnAboutMissingAppId.js'\nimport {determineBasePath} from './determineBasePath.js'\nimport {type BuildOptions} from './types.js'\n\n/**\n * Build the Sanity Studio.\n *\n * @internal\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n const {calledFromDeploy, cliConfig, flags, outDir, output, workDir} = options\n\n // `views`/`services` live on the branded `unstable_defineApp` result — resolve\n // the workbench capability so it's gated on the brand, like the app build.\n const workbench = resolveWorkbenchApp(cliConfig)\n\n const appId = getAppId(cliConfig)\n\n const upgradePkgs = async (options: {\n packages: [name: string, version: string][]\n }): Promise<void> => {\n await upgradePackages(\n {\n packageManager: (await getPackageManagerChoice(workDir, {interactive: false})).chosen,\n packages: options.packages,\n },\n {output, workDir},\n )\n }\n\n await internalBuildStudio({\n appId,\n autoUpdatesEnabled: options.autoUpdatesEnabled,\n checkAppId: () => {\n // Warn if auto updates enabled but no appId configured.\n // Skip when called from deploy, since deploy handles appId itself\n // (prompts the user and tells them to add it to config).\n if (!appId && !calledFromDeploy) {\n warnAboutMissingAppId({appType: 'studio', output, projectId: cliConfig?.api?.projectId})\n }\n },\n compareDependencyVersions: (packages) => compareDependencyVersions(packages, workDir, {appId}),\n determineBasePath: () => determineBasePath(cliConfig, 'studio', output),\n exposes: workbench ? {services: workbench.services, views: workbench.views} : undefined,\n isApp: determineIsApp(cliConfig),\n isWorkbenchApp: !!workbench,\n minify: Boolean(flags.minify),\n outDir,\n output,\n reactCompiler: cliConfig.reactCompiler,\n schemaExtraction: cliConfig.schemaExtraction,\n sourceMap: Boolean(flags['source-maps']),\n stats: flags.stats,\n unattendedMode: Boolean(flags.yes),\n upgradePackages: upgradePkgs,\n vite: cliConfig.vite,\n workbenchAppId: workbench?.name,\n workDir,\n })\n}\n"],"names":["compareDependencyVersions","buildStudio","internalBuildStudio","resolveWorkbenchApp","getAppId","determineIsApp","getPackageManagerChoice","upgradePackages","warnAboutMissingAppId","determineBasePath","options","calledFromDeploy","cliConfig","flags","outDir","output","workDir","workbench","appId","upgradePkgs","packageManager","interactive","chosen","packages","autoUpdatesEnabled","checkAppId","appType","projectId","api","exposes","services","views","undefined","isApp","isWorkbenchApp","minify","Boolean","reactCompiler","schemaExtraction","sourceMap","stats","unattendedMode","yes","vite","workbenchAppId","name"],"mappings":"AAAA,SACEA,yBAAyB,EACzBC,eAAeC,mBAAmB,QAC7B,oCAAmC;AAC1C,SAAQC,mBAAmB,QAAO,8BAA6B;AAE/D,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,cAAc,QAAO,+BAA8B;AAC3D,SAAQC,uBAAuB,QAAO,oDAAmD;AACzF,SAAQC,eAAe,QAAO,+CAA8C;AAC5E,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,iBAAiB,QAAO,yBAAwB;AAGxD;;;;CAIC,GACD,OAAO,eAAeR,YAAYS,OAAqB;IACrD,MAAM,EAACC,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,EAAEC,OAAO,EAAC,GAAGN;IAEtE,+EAA+E;IAC/E,2EAA2E;IAC3E,MAAMO,YAAYd,oBAAoBS;IAEtC,MAAMM,QAAQd,SAASQ;IAEvB,MAAMO,cAAc,OAAOT;QAGzB,MAAMH,gBACJ;YACEa,gBAAgB,AAAC,CAAA,MAAMd,wBAAwBU,SAAS;gBAACK,aAAa;YAAK,EAAC,EAAGC,MAAM;YACrFC,UAAUb,QAAQa,QAAQ;QAC5B,GACA;YAACR;YAAQC;QAAO;IAEpB;IAEA,MAAMd,oBAAoB;QACxBgB;QACAM,oBAAoBd,QAAQc,kBAAkB;QAC9CC,YAAY;YACV,wDAAwD;YACxD,kEAAkE;YAClE,yDAAyD;YACzD,IAAI,CAACP,SAAS,CAACP,kBAAkB;gBAC/BH,sBAAsB;oBAACkB,SAAS;oBAAUX;oBAAQY,WAAWf,WAAWgB,KAAKD;gBAAS;YACxF;QACF;QACA3B,2BAA2B,CAACuB,WAAavB,0BAA0BuB,UAAUP,SAAS;gBAACE;YAAK;QAC5FT,mBAAmB,IAAMA,kBAAkBG,WAAW,UAAUG;QAChEc,SAASZ,YAAY;YAACa,UAAUb,UAAUa,QAAQ;YAAEC,OAAOd,UAAUc,KAAK;QAAA,IAAIC;QAC9EC,OAAO5B,eAAeO;QACtBsB,gBAAgB,CAAC,CAACjB;QAClBkB,QAAQC,QAAQvB,MAAMsB,MAAM;QAC5BrB;QACAC;QACAsB,eAAezB,UAAUyB,aAAa;QACtCC,kBAAkB1B,UAAU0B,gBAAgB;QAC5CC,WAAWH,QAAQvB,KAAK,CAAC,cAAc;QACvC2B,OAAO3B,MAAM2B,KAAK;QAClBC,gBAAgBL,QAAQvB,MAAM6B,GAAG;QACjCnC,iBAAiBY;QACjBwB,MAAM/B,UAAU+B,IAAI;QACpBC,gBAAgB3B,WAAW4B;QAC3B7B;IACF;AACF"}
@@ -5,6 +5,13 @@ import { createUserApplication as createUserApplicationRequest } from '../../ser
5
5
  import { NO_ORGANIZATION_ID } from '../../util/errorMessages.js';
6
6
  import { deployDebug } from './deployDebug.js';
7
7
  import { normalizeUrl, validateUrl } from './urlUtils.js';
8
+ const LETTERS = 'abcdefghijklmnopqrstuvwxyz';
9
+ // appHosts have some restrictions (no uppercase, must start with a letter)
10
+ export function generateAppSlug() {
11
+ const firstChar = customAlphabet(LETTERS, 1)();
12
+ const rest = customAlphabet(`${LETTERS}0123456789`, 11)();
13
+ return `${firstChar}${rest}`;
14
+ }
8
15
  // TODO: replace with `Promise.withResolvers()` once it lands in node 22
9
16
  function promiseWithResolvers() {
10
17
  let resolve;
@@ -81,16 +88,9 @@ export async function createUserApplication(organizationId, title) {
81
88
  });
82
89
  return tryCreateApp(resolvedTitle, organizationId);
83
90
  }
84
- // appHosts have some restrictions (no uppercase, must start with a letter)
85
- const generateId = ()=>{
86
- const letters = 'abcdefghijklmnopqrstuvwxyz';
87
- const firstChar = customAlphabet(letters, 1)();
88
- const rest = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 11)();
89
- return `${firstChar}${rest}`;
90
- };
91
91
  const tryCreateApp = async (title, organizationId)=>{
92
92
  // we will likely prepend this with an org ID or other parameter in the future
93
- const appHost = generateId();
93
+ const appHost = generateAppSlug();
94
94
  const spin = spinner('Creating application').start();
95
95
  try {
96
96
  const response = await createUserApplicationRequest({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/createUserApplication.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {customAlphabet} from 'nanoid'\n\nimport {\n createUserApplication as createUserApplicationRequest,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {deployDebug} from './deployDebug.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\n// TODO: replace with `Promise.withResolvers()` once it lands in node 22\nfunction promiseWithResolvers<T>() {\n let resolve!: (t: T) => void\n let reject!: (err: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {promise, reject, resolve}\n}\n\ninterface CreateStudioUserApplicationOptions {\n projectId: string\n\n title?: string\n urlType?: 'external' | 'internal'\n}\n\nexport async function createStudioUserApplication(options: CreateStudioUserApplicationOptions) {\n const {projectId, title, urlType = 'internal'} = options\n const {promise, resolve} = promiseWithResolvers<UserApplication>()\n\n const isExternal = urlType === 'external'\n\n await input({\n message: isExternal ? 'Studio URL (https://...):' : 'Studio hostname (<value>.sanity.studio):',\n // if a string is returned here, it is relayed to the user and prompt allows\n // the user to try again until this function returns true\n validate: async (inp: string) => {\n let appHost: string\n\n if (isExternal) {\n const normalized = normalizeUrl(inp)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return validation\n }\n appHost = normalized\n } else {\n appHost = inp.replace(/\\.sanity\\.studio$/i, '')\n }\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n resolve(response)\n return true\n } catch (e) {\n // if the name is taken, it should return a 409 so we relay to the user\n if ([402, 409].includes(e?.statusCode)) {\n return e?.response?.body?.message || 'Bad request' // just in case\n }\n\n deployDebug('Error creating user application', e)\n // otherwise, it's a fatal error\n throw new CLIError('Error creating user application', {exit: 1})\n }\n },\n })\n\n return await promise\n}\n\nexport async function createUserApplication(\n organizationId?: string,\n title?: string,\n): Promise<UserApplicationResolved> {\n if (!organizationId) {\n throw new Error(NO_ORGANIZATION_ID)\n }\n\n const resolvedTitle =\n title ??\n (await input({\n message: 'Enter a title for your application:',\n validate: (value: string) => value.length > 0 || 'Title is required',\n }))\n\n return tryCreateApp(resolvedTitle, organizationId)\n}\n\n// appHosts have some restrictions (no uppercase, must start with a letter)\nconst generateId = () => {\n const letters = 'abcdefghijklmnopqrstuvwxyz'\n const firstChar = customAlphabet(letters, 1)()\n const rest = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 11)()\n return `${firstChar}${rest}`\n}\n\nconst tryCreateApp = async (title: string, organizationId: string) => {\n // we will likely prepend this with an org ID or other parameter in the future\n const appHost = generateId()\n\n const spin = spinner('Creating application').start()\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'coreApp',\n body: {appHost, title, type: 'coreApp', urlType: 'internal'},\n organizationId,\n })\n\n spin.succeed()\n return response\n } catch (e) {\n // if the name is taken, generate a new one and try again\n if ([402, 409].includes(e?.statusCode)) {\n deployDebug('App host taken, retrying with new host')\n return tryCreateApp(title, organizationId)\n }\n\n spin.fail()\n\n deployDebug('Error creating core application', e)\n throw e\n }\n}\n"],"names":["CLIError","input","spinner","customAlphabet","createUserApplication","createUserApplicationRequest","NO_ORGANIZATION_ID","deployDebug","normalizeUrl","validateUrl","promiseWithResolvers","resolve","reject","promise","Promise","res","rej","createStudioUserApplication","options","projectId","title","urlType","isExternal","message","validate","inp","appHost","normalized","validation","replace","response","appType","body","type","e","includes","statusCode","exit","organizationId","Error","resolvedTitle","value","length","tryCreateApp","generateId","letters","firstChar","rest","spin","start","succeed","fail"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/createUserApplication.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {customAlphabet} from 'nanoid'\n\nimport {\n createUserApplication as createUserApplicationRequest,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {deployDebug} from './deployDebug.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\nconst LETTERS = 'abcdefghijklmnopqrstuvwxyz'\n\n// appHosts have some restrictions (no uppercase, must start with a letter)\nexport function generateAppSlug(): string {\n const firstChar = customAlphabet(LETTERS, 1)()\n const rest = customAlphabet(`${LETTERS}0123456789`, 11)()\n return `${firstChar}${rest}`\n}\n\n// TODO: replace with `Promise.withResolvers()` once it lands in node 22\nfunction promiseWithResolvers<T>() {\n let resolve!: (t: T) => void\n let reject!: (err: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {promise, reject, resolve}\n}\n\ninterface CreateStudioUserApplicationOptions {\n projectId: string\n\n title?: string\n urlType?: 'external' | 'internal'\n}\n\nexport async function createStudioUserApplication(options: CreateStudioUserApplicationOptions) {\n const {projectId, title, urlType = 'internal'} = options\n const {promise, resolve} = promiseWithResolvers<UserApplication>()\n\n const isExternal = urlType === 'external'\n\n await input({\n message: isExternal ? 'Studio URL (https://...):' : 'Studio hostname (<value>.sanity.studio):',\n // if a string is returned here, it is relayed to the user and prompt allows\n // the user to try again until this function returns true\n validate: async (inp: string) => {\n let appHost: string\n\n if (isExternal) {\n const normalized = normalizeUrl(inp)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return validation\n }\n appHost = normalized\n } else {\n appHost = inp.replace(/\\.sanity\\.studio$/i, '')\n }\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n resolve(response)\n return true\n } catch (e) {\n // if the name is taken, it should return a 409 so we relay to the user\n if ([402, 409].includes(e?.statusCode)) {\n return e?.response?.body?.message || 'Bad request' // just in case\n }\n\n deployDebug('Error creating user application', e)\n // otherwise, it's a fatal error\n throw new CLIError('Error creating user application', {exit: 1})\n }\n },\n })\n\n return await promise\n}\n\nexport async function createUserApplication(\n organizationId?: string,\n title?: string,\n): Promise<UserApplicationResolved> {\n if (!organizationId) {\n throw new Error(NO_ORGANIZATION_ID)\n }\n\n const resolvedTitle =\n title ??\n (await input({\n message: 'Enter a title for your application:',\n validate: (value: string) => value.length > 0 || 'Title is required',\n }))\n\n return tryCreateApp(resolvedTitle, organizationId)\n}\n\nconst tryCreateApp = async (title: string, organizationId: string) => {\n // we will likely prepend this with an org ID or other parameter in the future\n const appHost = generateAppSlug()\n\n const spin = spinner('Creating application').start()\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'coreApp',\n body: {appHost, title, type: 'coreApp', urlType: 'internal'},\n organizationId,\n })\n\n spin.succeed()\n return response\n } catch (e) {\n // if the name is taken, generate a new one and try again\n if ([402, 409].includes(e?.statusCode)) {\n deployDebug('App host taken, retrying with new host')\n return tryCreateApp(title, organizationId)\n }\n\n spin.fail()\n\n deployDebug('Error creating core application', e)\n throw e\n }\n}\n"],"names":["CLIError","input","spinner","customAlphabet","createUserApplication","createUserApplicationRequest","NO_ORGANIZATION_ID","deployDebug","normalizeUrl","validateUrl","LETTERS","generateAppSlug","firstChar","rest","promiseWithResolvers","resolve","reject","promise","Promise","res","rej","createStudioUserApplication","options","projectId","title","urlType","isExternal","message","validate","inp","appHost","normalized","validation","replace","response","appType","body","type","e","includes","statusCode","exit","organizationId","Error","resolvedTitle","value","length","tryCreateApp","spin","start","succeed","fail"],"mappings":"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"}
@@ -2,22 +2,22 @@ import { basename, dirname } from 'node:path';
2
2
  import { styleText } from 'node:util';
3
3
  import { createGzip } from 'node:zlib';
4
4
  import { exitCodes } from '@sanity/cli-core';
5
+ import { getErrorMessage } from '@sanity/cli-core/errors';
6
+ import { getCoreAppUrl } from '@sanity/cli-core/util';
5
7
  import { spinner } from '@sanity/cli-core/ux';
6
- import { deployInstallationConfig, getWorkbench, resolveInstallationId, summarizeInstallationConfig } from '@sanity/workbench-cli/deploy';
8
+ import { buildExposes, deployConfig, deployCoreApp as deployWorkbenchCoreApp, getApplicationUrl, getWorkbench, resolveInstallationId, summarizeConfig } from '@sanity/workbench-cli/deploy';
7
9
  import { pack } from 'tar-fs';
8
10
  import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
9
11
  import { getAppId } from '../../util/appId.js';
10
12
  import { EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID } from '../../util/errorMessages.js';
11
- import { getErrorMessage } from '../../util/getErrorMessage.js';
12
13
  import { buildApp } from '../build/buildApp.js';
13
14
  import { extractCoreAppManifest, resolveTitleUpdate } from '../manifest/extractCoreAppManifest.js';
14
- import { createUserApplication } from './createUserApplication.js';
15
+ import { createUserApplication, generateAppSlug } from './createUserApplication.js';
15
16
  import { checkAppId, checkAppTarget, checkAutoUpdates, checkBuild, checkPackageVersion, verifyOutputDir } from './deployChecks.js';
16
17
  import { deployDebug } from './deployDebug.js';
17
- import { listDeploymentFiles } from './deploymentPlan.js';
18
+ import { listDeploymentFiles, reportExposes } from './deploymentPlan.js';
18
19
  import { runDeploy } from './deployRunner.js';
19
20
  import { findUserApplication } from './findUserApplication.js';
20
- import { getCoreAppUrl } from './urlUtils.js';
21
21
  const APP_PACKAGE = '@sanity/sdk-react';
22
22
  export function deployApp(options) {
23
23
  return runDeploy(options, {
@@ -30,12 +30,14 @@ export function deployApp(options) {
30
30
  const { cliConfig, flags, output, sourceDir } = options;
31
31
  const workDir = options.projectRoot.directory;
32
32
  const organizationId = cliConfig.app?.organizationId;
33
+ const appId = getAppId(cliConfig);
33
34
  const workbench = getWorkbench(cliConfig);
34
35
  const dryRun = !!flags['dry-run'];
35
36
  // A singleton (the Media Library) persists its config instead of hosting an
36
- // application; anything with interfaces still ships one.
37
- const deploySingletonInstallationConfig = workbench?.deploySingletonInstallationConfig ?? false;
37
+ // application; anything that exposes a view or service still ships one.
38
+ const deploySingletonConfig = workbench?.deploySingletonConfig ?? false;
38
39
  const deployApplication = !workbench || workbench.hasInterfaces;
40
+ const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name : '';
39
41
  // A federated app with no entry, view or service would ship a remote with
40
42
  // nothing to load — reported first so it fails before any prompt or API call.
41
43
  if (workbench) {
@@ -62,7 +64,7 @@ export function deployApp(options) {
62
64
  moduleName: APP_PACKAGE,
63
65
  workDir
64
66
  });
65
- } else if (deploySingletonInstallationConfig) {
67
+ } else if (deploySingletonConfig) {
66
68
  version = await checkPackageVersion(reporter, {
67
69
  moduleName: 'sanity',
68
70
  workDir
@@ -80,17 +82,26 @@ export function deployApp(options) {
80
82
  cliConfig
81
83
  });
82
84
  let application = null;
85
+ let appCreated = false;
83
86
  if (flags.external) {
84
87
  reporter.report({
85
88
  message: EXTERNAL_APP_NOT_SUPPORTED,
86
89
  solution: 'Remove the --external flag — apps deploy to Sanity hosting',
87
90
  status: 'fail'
88
91
  });
92
+ } else if (deployApplication && workbench) {
93
+ await checkAppTarget(reporter, {
94
+ appId,
95
+ isWorkbenchApp: true,
96
+ slug: workbench.slug,
97
+ title: appTitle
98
+ });
89
99
  } else if (deployApplication) {
90
- application = await resolveAppApplication(options, {
100
+ ;
101
+ ({ application, created: appCreated } = await resolveAppApplication(options, {
91
102
  dryRun,
92
103
  reporter
93
- });
104
+ }));
94
105
  }
95
106
  await checkBuild(reporter, {
96
107
  build: ()=>buildApp({
@@ -126,14 +137,17 @@ export function deployApp(options) {
126
137
  // Resolve the installation in both modes so the report — dry-run and real —
127
138
  // shows whether the config is deployable; a missing one fails the deploy here.
128
139
  let installationId;
129
- const configAppType = workbench?.installationConfig?.appType;
130
- if (deploySingletonInstallationConfig && organizationId && workbench?.installationConfig && configAppType) {
140
+ let config;
141
+ const configAppType = workbench?.config?.appType;
142
+ if (deploySingletonConfig && organizationId && workbench?.config && configAppType) {
131
143
  installationId = await resolveInstallationId({
132
144
  appType: configAppType,
133
145
  organizationId
134
146
  });
147
+ config = summarizeConfig(workbench.config);
135
148
  reporter.report(installationId ? {
136
- message: summarizeInstallationConfig(workbench.installationConfig),
149
+ config,
150
+ message: config,
137
151
  status: 'pass'
138
152
  } : {
139
153
  exitCode: exitCodes.USAGE_ERROR,
@@ -142,32 +156,103 @@ export function deployApp(options) {
142
156
  status: 'fail'
143
157
  });
144
158
  }
159
+ // Report the exposes deploying with the application, both modes.
160
+ const exposes = deployApplication && workbench ? reportExposes(reporter, workbench) : [];
161
+ // Surface the app's explicit singleton flag when set, both modes.
162
+ if (deployApplication && workbench?.isSingleton !== undefined) {
163
+ reporter.report({
164
+ isSingleton: workbench.isSingleton,
165
+ message: `Singleton: ${workbench.isSingleton}`,
166
+ status: 'pass'
167
+ });
168
+ }
145
169
  // Dry run stops here — everything below mutates.
146
170
  if (dryRun) return;
147
- if (installationId && version && configAppType) {
148
- await deployInstallationConfig({
171
+ if (installationId && version && configAppType && organizationId) {
172
+ await deployConfig({
149
173
  appType: configAppType,
150
174
  installationId,
175
+ organizationId,
151
176
  output,
152
177
  sourceDir,
153
178
  version
154
179
  });
155
180
  }
156
- // A config-only singleton ships no application, only its installation config.
181
+ // A config-only singleton ships no application, only its config.
157
182
  if (!deployApplication) {
158
183
  if (installationId && version) {
159
184
  return {
160
185
  applicationType: 'coreApp',
161
186
  applicationVersion: version,
187
+ ...config ? {
188
+ config
189
+ } : {},
162
190
  installationId,
163
191
  target: null
164
192
  };
165
193
  }
166
194
  return;
167
195
  }
196
+ // A real deploy already exited on a version-resolution failure; this narrows the type.
197
+ if (!version) return;
198
+ // Workbench apps deploy to Brett; plain coreApps use user-applications.
199
+ if (workbench && organizationId) {
200
+ const appId = getAppId(cliConfig);
201
+ const slug = workbench.slug ?? generateAppSlug();
202
+ const { applicationId } = await deployWorkbenchCoreApp({
203
+ appId,
204
+ interfaces: buildExposes(workbench, {
205
+ appName: workbench.name,
206
+ appTitle,
207
+ exposesAppView: workbench.entry !== undefined,
208
+ version
209
+ }),
210
+ isAutoUpdating,
211
+ isSingleton: workbench.isSingleton,
212
+ organizationId,
213
+ slug,
214
+ sourceDir,
215
+ title: appTitle,
216
+ version
217
+ });
218
+ const url = getApplicationUrl({
219
+ id: applicationId,
220
+ organizationId,
221
+ type: 'coreApp'
222
+ });
223
+ logAppDeployed({
224
+ applicationId,
225
+ cliConfig,
226
+ created: !appId,
227
+ organizationId,
228
+ output,
229
+ title: appTitle,
230
+ url
231
+ });
232
+ return {
233
+ applicationType: 'coreApp',
234
+ applicationVersion: version,
235
+ ...exposes.length > 0 ? {
236
+ exposes
237
+ } : {},
238
+ ...workbench.isSingleton === undefined ? {} : {
239
+ isSingleton: workbench.isSingleton
240
+ },
241
+ target: {
242
+ action: appId ? 'update' : 'create',
243
+ applicationId,
244
+ // A redeploy ignores the slug, so only a create reports the one it used.
245
+ ...appId ? {} : {
246
+ slug
247
+ },
248
+ title: appTitle,
249
+ url
250
+ }
251
+ };
252
+ }
168
253
  // A real deploy has already exited if anything failed; landing here without a
169
- // resolved application or version means the deploy target was never resolved.
170
- if (!application || !version) return;
254
+ // resolved application means the deploy target was never resolved.
255
+ if (!application) return;
171
256
  application = await syncApplicationTitle({
172
257
  application,
173
258
  manifest,
@@ -181,14 +266,18 @@ export function deployApp(options) {
181
266
  version
182
267
  });
183
268
  logAppDeployed({
184
- application,
269
+ applicationId: application.id,
185
270
  cliConfig,
186
- output
271
+ created: appCreated,
272
+ organizationId: application.organizationId,
273
+ output,
274
+ title: application.title
187
275
  });
188
276
  return {
189
277
  applicationType: 'coreApp',
190
278
  applicationVersion: version,
191
279
  target: {
280
+ action: appCreated ? 'create' : 'update',
192
281
  applicationId: application.id,
193
282
  title: application.title ?? null,
194
283
  url: getCoreAppUrl(application.organizationId, application.id)
@@ -209,7 +298,10 @@ export function deployApp(options) {
209
298
  organizationId,
210
299
  title
211
300
  });
212
- return null;
301
+ return {
302
+ application: null,
303
+ created: false
304
+ };
213
305
  }
214
306
  let application = await findUserApplication({
215
307
  cliConfig,
@@ -223,8 +315,15 @@ export function deployApp(options) {
223
315
  deployDebug('No user application found. Creating a new one');
224
316
  application = await createUserApplication(organizationId, title);
225
317
  deployDebug('User application created', application);
318
+ return {
319
+ application,
320
+ created: true
321
+ };
226
322
  }
227
- return application;
323
+ return {
324
+ application,
325
+ created: false
326
+ };
228
327
  }
229
328
  /** Syncs the application title from the manifest when it has changed. */ async function syncApplicationTitle({ application, manifest, output }) {
230
329
  const titleUpdate = resolveTitleUpdate(manifest, application);
@@ -274,12 +373,15 @@ async function shipAppDeployment({ application, isAutoUpdating, manifest, source
274
373
  }
275
374
  spin.succeed();
276
375
  }
277
- export function logAppDeployed({ application, cliConfig, output }) {
278
- const url = getCoreAppUrl(application.organizationId, application.id);
279
- const named = application.title ? ` — "${application.title}"` : '';
376
+ export function logAppDeployed({ applicationId, cliConfig, created, organizationId, output, title, url = getCoreAppUrl(organizationId, applicationId) }) {
377
+ const named = title ? ` — "${title}"` : '';
280
378
  output.log(`\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`);
379
+ output.log(created ? 'Created a new application.' : 'Updated the existing application.');
281
380
  if (getAppId(cliConfig)) return;
282
381
  output.log(`\n════ ${styleText('bold', 'Next step:')} ════`);
382
+ if (created) {
383
+ output.log(styleText('yellow', '\nDeploying again without `deployment.appId` creates another new application.'));
384
+ }
283
385
  output.log(styleText('bold', '\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'));
284
386
  output.log(`
285
387
  ${styleText('dim', `app: {
@@ -289,7 +391,7 @@ ${styleText([
289
391
  'bold',
290
392
  'green'
291
393
  ], `deployment: {
292
- appId: '${application.id}',
394
+ appId: '${applicationId}',
293
395
  }\n`)}`);
294
396
  }
295
397