@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
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/tokens/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\n\nimport {type Token} from '../../actions/tokens/types.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {getErrorMessage} from '../../util/getErrorMessage.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for the project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output tokens in JSON format',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.tokens'}],\n }),\n })\n\n let tokens: Token[]\n try {\n tokens = await getTokens(projectId)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for project ${projectId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: 1})\n }\n\n if (outputJson) {\n this.log(JSON.stringify(tokens, null, 2))\n return\n }\n\n if (tokens.length === 0) {\n this.log('No API tokens found for this project.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 40, name: 'label', title: 'Label'},\n {alignment: 'left', maxLen: 20, name: 'id', title: 'Token ID'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = token.roles?.map((role) => role.title).join(', ') || 'No roles'\n const truncatedLabel =\n token.label.length > 37 ? `${token.label.slice(0, 37)}...` : token.label\n const truncatedRoles = roles.length > 27 ? `${roles.slice(0, 27)}...` : roles\n\n table.addRow({\n id: token.id,\n label: truncatedLabel,\n roles: truncatedRoles,\n })\n }\n\n table.printTable()\n }\n}\n"],"names":["Flags","SanityCommand","subdebug","Table","promptForProject","getTokens","getErrorMessage","getProjectIdFlag","listTokenDebug","TokensListCommand","description","examples","command","flags","semantics","json","boolean","default","hiddenAliases","run","parse","outputJson","projectId","getProjectId","fallback","requiredPermissions","grant","permission","tokens","error","message","exit","log","JSON","stringify","length","table","columns","alignment","maxLen","name","title","token","roles","map","role","join","truncatedLabel","label","slice","truncatedRoles","addRow","id","printTable"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,KAAK,QAAO,wBAAuB;AAG3C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,eAAe,QAAO,gCAA+B;AAC7D,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,iBAAiBN,SAAS;AAEhC,OAAO,MAAMO,0BAA0BR;IACrC,OAAgBS,cAAc,kCAAiC;IAC/D,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;QACFC,MAAMf,MAAMgB,OAAO,CAAC;YAClBC,SAAS;YACTP,aAAa;QACf;IACF,EAAC;IAED,OAAgBQ,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACX;QACjC,MAAM,EAACM,IAAI,EAAC,GAAGF;QACf,MAAMQ,aAAaN,QAAQ;QAE3B,iCAAiC;QACjC,MAAMO,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRpB,iBAAiB;oBACfqB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAuB;qBAAE;gBAC7E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMvB,UAAUiB;QAC3B,EAAE,OAAOO,OAAO;YACd,MAAMC,UAAUxB,gBAAgBuB;YAChCrB,eAAe,CAAC,kCAAkC,EAAEc,WAAW,EAAEO;YACjE,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACC,MAAM;YAAC;QACjE;QAEA,IAAIV,YAAY;YACd,IAAI,CAACW,GAAG,CAACC,KAAKC,SAAS,CAACN,QAAQ,MAAM;YACtC;QACF;QAEA,IAAIA,OAAOO,MAAM,KAAK,GAAG;YACvB,IAAI,CAACH,GAAG,CAAC;YACT;QACF;QAEA,MAAMI,QAAQ,IAAIjC,MAAM;YACtBkC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAAMC,OAAO;gBAAU;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;aAC9D;YACDA,OAAO,CAAC,MAAM,EAAEb,OAAOO,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMO,SAASd,OAAQ;YAC1B,MAAMe,QAAQD,MAAMC,KAAK,EAAEC,IAAI,CAACC,OAASA,KAAKJ,KAAK,EAAEK,KAAK,SAAS;YACnE,MAAMC,iBACJL,MAAMM,KAAK,CAACb,MAAM,GAAG,KAAK,GAAGO,MAAMM,KAAK,CAACC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGP,MAAMM,KAAK;YAC1E,MAAME,iBAAiBP,MAAMR,MAAM,GAAG,KAAK,GAAGQ,MAAMM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGN;YAExEP,MAAMe,MAAM,CAAC;gBACXC,IAAIV,MAAMU,EAAE;gBACZJ,OAAOD;gBACPJ,OAAOO;YACT;QACF;QAEAd,MAAMiB,UAAU;IAClB;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/tokens/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {Table} from 'console-table-printer'\n\nimport {type Token} from '../../actions/tokens/types.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for the project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output tokens in JSON format',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.tokens'}],\n }),\n })\n\n let tokens: Token[]\n try {\n tokens = await getTokens(projectId)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for project ${projectId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: 1})\n }\n\n if (outputJson) {\n this.log(JSON.stringify(tokens, null, 2))\n return\n }\n\n if (tokens.length === 0) {\n this.log('No API tokens found for this project.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 40, name: 'label', title: 'Label'},\n {alignment: 'left', maxLen: 20, name: 'id', title: 'Token ID'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = token.roles?.map((role) => role.title).join(', ') || 'No roles'\n const truncatedLabel =\n token.label.length > 37 ? `${token.label.slice(0, 37)}...` : token.label\n const truncatedRoles = roles.length > 27 ? `${roles.slice(0, 27)}...` : roles\n\n table.addRow({\n id: token.id,\n label: truncatedLabel,\n roles: truncatedRoles,\n })\n }\n\n table.printTable()\n }\n}\n"],"names":["Flags","SanityCommand","subdebug","getErrorMessage","Table","promptForProject","getTokens","getProjectIdFlag","listTokenDebug","TokensListCommand","description","examples","command","flags","semantics","json","boolean","default","hiddenAliases","run","parse","outputJson","projectId","getProjectId","fallback","requiredPermissions","grant","permission","tokens","error","message","exit","log","JSON","stringify","length","table","columns","alignment","maxLen","name","title","token","roles","map","role","join","truncatedLabel","label","slice","truncatedRoles","addRow","id","printTable"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,KAAK,QAAO,wBAAuB;AAG3C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,iBAAiBN,SAAS;AAEhC,OAAO,MAAMO,0BAA0BR;IACrC,OAAgBS,cAAc,kCAAiC;IAC/D,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;QACFC,MAAMf,MAAMgB,OAAO,CAAC;YAClBC,SAAS;YACTP,aAAa;QACf;IACF,EAAC;IAED,OAAgBQ,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACX;QACjC,MAAM,EAACM,IAAI,EAAC,GAAGF;QACf,MAAMQ,aAAaN,QAAQ;QAE3B,iCAAiC;QACjC,MAAMO,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAuB;qBAAE;gBAC7E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMtB,UAAUgB;QAC3B,EAAE,OAAOO,OAAO;YACd,MAAMC,UAAU3B,gBAAgB0B;YAChCrB,eAAe,CAAC,kCAAkC,EAAEc,WAAW,EAAEO;YACjE,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACC,MAAM;YAAC;QACjE;QAEA,IAAIV,YAAY;YACd,IAAI,CAACW,GAAG,CAACC,KAAKC,SAAS,CAACN,QAAQ,MAAM;YACtC;QACF;QAEA,IAAIA,OAAOO,MAAM,KAAK,GAAG;YACvB,IAAI,CAACH,GAAG,CAAC;YACT;QACF;QAEA,MAAMI,QAAQ,IAAIhC,MAAM;YACtBiC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAAMC,OAAO;gBAAU;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;aAC9D;YACDA,OAAO,CAAC,MAAM,EAAEb,OAAOO,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMO,SAASd,OAAQ;YAC1B,MAAMe,QAAQD,MAAMC,KAAK,EAAEC,IAAI,CAACC,OAASA,KAAKJ,KAAK,EAAEK,KAAK,SAAS;YACnE,MAAMC,iBACJL,MAAMM,KAAK,CAACb,MAAM,GAAG,KAAK,GAAGO,MAAMM,KAAK,CAACC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGP,MAAMM,KAAK;YAC1E,MAAME,iBAAiBP,MAAMR,MAAM,GAAG,KAAK,GAAGQ,MAAMM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGN;YAExEP,MAAMe,MAAM,CAAC;gBACXC,IAAIV,MAAMU,EAAE;gBACZJ,OAAOD;gBACPJ,OAAOO;YACT;QACF;QAEAd,MAAMiB,UAAU;IAClB;AACF"}
@@ -1,13 +1,37 @@
1
- import { styleText } from 'node:util';
2
1
  import { Flags } from '@oclif/core';
3
2
  import { SanityCommand } from '@sanity/cli-core';
4
- import { confirm, spinner } from '@sanity/cli-core/ux';
5
- import { getStudioOrAppUserApplication, NO_APP_ID, NO_APP_ID_OR_STUDIO_HOST } from '../actions/undeploy/getStudioOrAppUserApplication.js';
6
- import { deleteUserApplication } from '../services/userApplications.js';
3
+ import { getWorkbench } from '@sanity/workbench-cli/deploy';
4
+ import { createWorkbenchUndeployAdapter } from '@sanity/workbench-cli/undeploy';
5
+ import { createAppUndeployAdapter, createStudioUndeployAdapter } from '../actions/undeploy/adapters.js';
6
+ import { runUndeploy } from '../actions/undeploy/runUndeploy.js';
7
+ import { getAppId } from '../util/appId.js';
7
8
  import { determineIsApp } from '../util/determineIsApp.js';
8
9
  export class UndeployCommand extends SanityCommand {
9
10
  static description = 'Removes the deployed Sanity Studio/App from Sanity hosting';
11
+ static examples = [
12
+ {
13
+ command: '<%= config.bin %> <%= command.id %>',
14
+ description: 'Undeploy the studio or application after confirming'
15
+ },
16
+ {
17
+ command: '<%= config.bin %> <%= command.id %> --dry-run',
18
+ description: 'Report what would be undeployed without deleting anything'
19
+ },
20
+ {
21
+ command: '<%= config.bin %> <%= command.id %> --json --yes',
22
+ description: 'Undeploy without prompting and report the result as JSON'
23
+ }
24
+ ];
10
25
  static flags = {
26
+ 'dry-run': Flags.boolean({
27
+ default: false,
28
+ description: 'Report what would be undeployed without deleting anything'
29
+ }),
30
+ json: Flags.boolean({
31
+ char: 'j',
32
+ default: false,
33
+ description: 'Output the result as JSON'
34
+ }),
11
35
  yes: Flags.boolean({
12
36
  char: 'y',
13
37
  default: false,
@@ -17,76 +41,26 @@ export class UndeployCommand extends SanityCommand {
17
41
  async run() {
18
42
  const { flags } = await this.parse(UndeployCommand);
19
43
  const cliConfig = await this.getCliConfig();
20
- const output = this.output;
21
44
  const isApp = determineIsApp(cliConfig);
22
- let spin = spinner('Checking application info').start();
23
- try {
24
- const userApplication = await getStudioOrAppUserApplication({
25
- cliConfig,
26
- output
27
- });
28
- if (!userApplication) {
29
- spin.fail();
30
- if (isApp) {
31
- this.log('Application with the given ID does not exist.');
32
- this.log('Nothing to undeploy.');
33
- } else {
34
- this.log('Your project has not been assigned an app ID or a studio hostname,');
35
- this.log('or the `appId` or `studioHost` provided does not exist.');
36
- this.log('Nothing to undeploy.');
37
- }
38
- return;
39
- }
40
- spin.succeed();
41
- const url = `https://${styleText('yellow', userApplication.appHost)}.sanity.studio`;
42
- if (!flags.yes) {
43
- let message = `This will undeploy ${url} and make it unavailable for your users.\nThe hostname will be available for anyone to claim.\nAre you ${styleText('red', 'sure')} you want to undeploy?`;
44
- if (isApp) {
45
- message = `This will undeploy the following application:
46
-
47
- Title: ${styleText('yellow', userApplication.title || '(untitled application)')}
48
- ID: ${styleText('yellow', userApplication.id)}
49
-
50
- The application will no longer be available for any of your users if you proceed.
51
-
52
- Are you ${styleText('red', 'sure')} you want to undeploy?`;
53
- }
54
- const shouldUndeploy = await confirm({
55
- default: false,
56
- message
57
- });
58
- if (!shouldUndeploy) {
59
- return;
60
- }
61
- }
62
- spin = spinner(`Undeploying ${isApp ? 'application' : 'studio'}`).start();
63
- await deleteUserApplication({
64
- applicationId: userApplication.id,
65
- appType: isApp ? 'coreApp' : 'studio'
66
- });
67
- spin.succeed();
68
- if (isApp) {
69
- this.log(`\n${styleText('bold', '⏱️ Application undeploy scheduled.')} It might be a few minutes until ${userApplication.title ? styleText('italic', `'${userApplication.title}'`) : 'your application'} is unavailable.`);
70
- this.log(`\n${styleText('bold', 'Remember to remove `deployment.appId` from your application configuration')} to avoid errors when redeploying.`);
71
- } else {
72
- this.log(`\nStudio undeploy scheduled. It might be a few minutes until ${url} is unavailable.`);
73
- }
74
- } catch (error) {
75
- spin.fail();
76
- if (error.message === NO_APP_ID) {
77
- this.log('No application ID provided.');
78
- this.log('Please set id in `deployment.appId` in sanity.cli.js or sanity.cli.ts.');
79
- this.log('Nothing to undeploy.');
80
- return;
81
- }
82
- if (error.message === NO_APP_ID_OR_STUDIO_HOST) {
83
- this.log('No application ID or studio host provided.');
84
- this.log('Please set id in `deployment.appId` in sanity.cli.js or sanity.cli.ts.');
85
- this.log('Nothing to undeploy.');
86
- return;
87
- }
88
- this.error(error);
89
- }
45
+ // Workbench apps deploy through Brett, so they undeploy through it too;
46
+ // plain projects keep the user-applications backend.
47
+ const workbench = getWorkbench(cliConfig);
48
+ const adapter = workbench ? createWorkbenchUndeployAdapter({
49
+ appId: getAppId(cliConfig),
50
+ organizationId: cliConfig.app?.organizationId,
51
+ type: isApp ? 'coreApp' : 'studio',
52
+ workbench
53
+ }) : isApp ? createAppUndeployAdapter(cliConfig) : createStudioUndeployAdapter(cliConfig);
54
+ // An unattended run (--yes, --json, non-TTY) can't answer the confirmation
55
+ // prompt, so it consents up front; machine callers preview with --dry-run.
56
+ const undeployFlags = this.isUnattended() ? {
57
+ ...flags,
58
+ yes: true
59
+ } : flags;
60
+ await runUndeploy({
61
+ flags: undeployFlags,
62
+ output: this.output
63
+ }, adapter);
90
64
  }
91
65
  }
92
66
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\n\nimport {\n getStudioOrAppUserApplication,\n NO_APP_ID,\n NO_APP_ID_OR_STUDIO_HOST,\n} from '../actions/undeploy/getStudioOrAppUserApplication.js'\nimport {deleteUserApplication} from '../services/userApplications.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override flags = {\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(UndeployCommand)\n\n const cliConfig = await this.getCliConfig()\n const output = this.output\n const isApp = determineIsApp(cliConfig)\n\n let spin = spinner('Checking application info').start()\n try {\n const userApplication = await getStudioOrAppUserApplication({cliConfig, output})\n if (!userApplication) {\n spin.fail()\n if (isApp) {\n this.log('Application with the given ID does not exist.')\n this.log('Nothing to undeploy.')\n } else {\n this.log('Your project has not been assigned an app ID or a studio hostname,')\n this.log('or the `appId` or `studioHost` provided does not exist.')\n this.log('Nothing to undeploy.')\n }\n\n return\n }\n spin.succeed()\n\n const url = `https://${styleText('yellow', userApplication.appHost)}.sanity.studio`\n\n if (!flags.yes) {\n let message = `This will undeploy ${url} and make it unavailable for your users.\\nThe hostname will be available for anyone to claim.\\nAre you ${styleText(\n 'red',\n 'sure',\n )} you want to undeploy?`\n\n if (isApp) {\n message = `This will undeploy the following application:\n\n Title: ${styleText('yellow', userApplication.title || '(untitled application)')}\n ID: ${styleText('yellow', userApplication.id)}\n\nThe application will no longer be available for any of your users if you proceed.\n\nAre you ${styleText('red', 'sure')} you want to undeploy?`\n }\n\n const shouldUndeploy = await confirm({\n default: false,\n message,\n })\n\n if (!shouldUndeploy) {\n return\n }\n }\n\n spin = spinner(`Undeploying ${isApp ? 'application' : 'studio'}`).start()\n\n await deleteUserApplication({\n applicationId: userApplication.id,\n appType: isApp ? 'coreApp' : 'studio',\n })\n spin.succeed()\n\n if (isApp) {\n this.log(\n `\\n${styleText('bold', '⏱️ Application undeploy scheduled.')} It might be a few minutes until ${\n userApplication.title\n ? styleText('italic', `'${userApplication.title}'`)\n : 'your application'\n } is unavailable.`,\n )\n this.log(\n `\\n${styleText('bold', 'Remember to remove `deployment.appId` from your application configuration')} to avoid errors when redeploying.`,\n )\n } else {\n this.log(\n `\\nStudio undeploy scheduled. It might be a few minutes until ${url} is unavailable.`,\n )\n }\n } catch (error) {\n spin.fail()\n if (error.message === NO_APP_ID) {\n this.log('No application ID provided.')\n this.log('Please set id in `deployment.appId` in sanity.cli.js or sanity.cli.ts.')\n this.log('Nothing to undeploy.')\n return\n }\n\n if (error.message === NO_APP_ID_OR_STUDIO_HOST) {\n this.log('No application ID or studio host provided.')\n this.log('Please set id in `deployment.appId` in sanity.cli.js or sanity.cli.ts.')\n this.log('Nothing to undeploy.')\n return\n }\n\n this.error(error)\n }\n }\n}\n"],"names":["styleText","Flags","SanityCommand","confirm","spinner","getStudioOrAppUserApplication","NO_APP_ID","NO_APP_ID_OR_STUDIO_HOST","deleteUserApplication","determineIsApp","UndeployCommand","description","flags","yes","boolean","char","default","run","parse","cliConfig","getCliConfig","output","isApp","spin","start","userApplication","fail","log","succeed","url","appHost","message","title","id","shouldUndeploy","applicationId","appType","error"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,QAAO,mBAAkB;AAC9C,SAAQC,OAAO,EAAEC,OAAO,QAAO,sBAAqB;AAEpD,SACEC,6BAA6B,EAC7BC,SAAS,EACTC,wBAAwB,QACnB,uDAAsD;AAC7D,SAAQC,qBAAqB,QAAO,kCAAiC;AACrE,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,wBAAwBR;IACnC,OAAgBS,cAAc,6DAA4D;IAE1F,OAAgBC,QAAQ;QACtBC,KAAKZ,MAAMa,OAAO,CAAC;YACjBC,MAAM;YACNC,SAAS;YACTL,aACE;QACJ;IACF,EAAC;IAED,MAAaM,MAAqB;QAChC,MAAM,EAACL,KAAK,EAAC,GAAG,MAAM,IAAI,CAACM,KAAK,CAACR;QAEjC,MAAMS,YAAY,MAAM,IAAI,CAACC,YAAY;QACzC,MAAMC,SAAS,IAAI,CAACA,MAAM;QAC1B,MAAMC,QAAQb,eAAeU;QAE7B,IAAII,OAAOnB,QAAQ,6BAA6BoB,KAAK;QACrD,IAAI;YACF,MAAMC,kBAAkB,MAAMpB,8BAA8B;gBAACc;gBAAWE;YAAM;YAC9E,IAAI,CAACI,iBAAiB;gBACpBF,KAAKG,IAAI;gBACT,IAAIJ,OAAO;oBACT,IAAI,CAACK,GAAG,CAAC;oBACT,IAAI,CAACA,GAAG,CAAC;gBACX,OAAO;oBACL,IAAI,CAACA,GAAG,CAAC;oBACT,IAAI,CAACA,GAAG,CAAC;oBACT,IAAI,CAACA,GAAG,CAAC;gBACX;gBAEA;YACF;YACAJ,KAAKK,OAAO;YAEZ,MAAMC,MAAM,CAAC,QAAQ,EAAE7B,UAAU,UAAUyB,gBAAgBK,OAAO,EAAE,cAAc,CAAC;YAEnF,IAAI,CAAClB,MAAMC,GAAG,EAAE;gBACd,IAAIkB,UAAU,CAAC,mBAAmB,EAAEF,IAAI,uGAAuG,EAAE7B,UAC/I,OACA,QACA,sBAAsB,CAAC;gBAEzB,IAAIsB,OAAO;oBACTS,UAAU,CAAC;;WAEV,EAAE/B,UAAU,UAAUyB,gBAAgBO,KAAK,IAAI,0BAA0B;WACzE,EAAEhC,UAAU,UAAUyB,gBAAgBQ,EAAE,EAAE;;;;QAI7C,EAAEjC,UAAU,OAAO,QAAQ,sBAAsB,CAAC;gBAClD;gBAEA,MAAMkC,iBAAiB,MAAM/B,QAAQ;oBACnCa,SAAS;oBACTe;gBACF;gBAEA,IAAI,CAACG,gBAAgB;oBACnB;gBACF;YACF;YAEAX,OAAOnB,QAAQ,CAAC,YAAY,EAAEkB,QAAQ,gBAAgB,UAAU,EAAEE,KAAK;YAEvE,MAAMhB,sBAAsB;gBAC1B2B,eAAeV,gBAAgBQ,EAAE;gBACjCG,SAASd,QAAQ,YAAY;YAC/B;YACAC,KAAKK,OAAO;YAEZ,IAAIN,OAAO;gBACT,IAAI,CAACK,GAAG,CACN,CAAC,EAAE,EAAE3B,UAAU,QAAQ,sCAAsC,iCAAiC,EAC5FyB,gBAAgBO,KAAK,GACjBhC,UAAU,UAAU,CAAC,CAAC,EAAEyB,gBAAgBO,KAAK,CAAC,CAAC,CAAC,IAChD,mBACL,gBAAgB,CAAC;gBAEpB,IAAI,CAACL,GAAG,CACN,CAAC,EAAE,EAAE3B,UAAU,QAAQ,6EAA6E,kCAAkC,CAAC;YAE3I,OAAO;gBACL,IAAI,CAAC2B,GAAG,CACN,CAAC,6DAA6D,EAAEE,IAAI,gBAAgB,CAAC;YAEzF;QACF,EAAE,OAAOQ,OAAO;YACdd,KAAKG,IAAI;YACT,IAAIW,MAAMN,OAAO,KAAKzB,WAAW;gBAC/B,IAAI,CAACqB,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CAAC;gBACT;YACF;YAEA,IAAIU,MAAMN,OAAO,KAAKxB,0BAA0B;gBAC9C,IAAI,CAACoB,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CAAC;gBACT;YACF;YAEA,IAAI,CAACU,KAAK,CAACA;QACb;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {type UndeployAdapter} from '@sanity/cli-core/undeploy'\nimport {getWorkbench} from '@sanity/workbench-cli/deploy'\nimport {createWorkbenchUndeployAdapter} from '@sanity/workbench-cli/undeploy'\n\nimport {\n createAppUndeployAdapter,\n createStudioUndeployAdapter,\n} from '../actions/undeploy/adapters.js'\nimport {runUndeploy} from '../actions/undeploy/runUndeploy.js'\nimport {getAppId} from '../util/appId.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Undeploy the studio or application after confirming',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --dry-run',\n description: 'Report what would be undeployed without deleting anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --yes',\n description: 'Undeploy without prompting and report the result as JSON',\n },\n ]\n\n static override flags = {\n 'dry-run': Flags.boolean({\n default: false,\n description: 'Report what would be undeployed without deleting anything',\n }),\n json: Flags.boolean({\n char: 'j',\n default: false,\n description: 'Output the result as JSON',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(UndeployCommand)\n\n const cliConfig = await this.getCliConfig()\n const isApp = determineIsApp(cliConfig)\n\n // Workbench apps deploy through Brett, so they undeploy through it too;\n // plain projects keep the user-applications backend.\n const workbench = getWorkbench(cliConfig)\n const adapter: UndeployAdapter = workbench\n ? createWorkbenchUndeployAdapter({\n appId: getAppId(cliConfig),\n organizationId: cliConfig.app?.organizationId,\n type: isApp ? 'coreApp' : 'studio',\n workbench,\n })\n : isApp\n ? createAppUndeployAdapter(cliConfig)\n : createStudioUndeployAdapter(cliConfig)\n\n // An unattended run (--yes, --json, non-TTY) can't answer the confirmation\n // prompt, so it consents up front; machine callers preview with --dry-run.\n const undeployFlags = this.isUnattended() ? {...flags, yes: true} : flags\n await runUndeploy({flags: undeployFlags, output: this.output}, adapter)\n }\n}\n"],"names":["Flags","SanityCommand","getWorkbench","createWorkbenchUndeployAdapter","createAppUndeployAdapter","createStudioUndeployAdapter","runUndeploy","getAppId","determineIsApp","UndeployCommand","description","examples","command","flags","boolean","default","json","char","yes","run","parse","cliConfig","getCliConfig","isApp","workbench","adapter","appId","organizationId","app","type","undeployFlags","isUnattended","output"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,QAAO,mBAAkB;AAE9C,SAAQC,YAAY,QAAO,+BAA8B;AACzD,SAAQC,8BAA8B,QAAO,iCAAgC;AAE7E,SACEC,wBAAwB,EACxBC,2BAA2B,QACtB,kCAAiC;AACxC,SAAQC,WAAW,QAAO,qCAAoC;AAC9D,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,wBAAwBR;IACnC,OAAgBS,cAAc,6DAA4D;IAE1F,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtB,WAAWb,MAAMc,OAAO,CAAC;YACvBC,SAAS;YACTL,aAAa;QACf;QACAM,MAAMhB,MAAMc,OAAO,CAAC;YAClBG,MAAM;YACNF,SAAS;YACTL,aAAa;QACf;QACAQ,KAAKlB,MAAMc,OAAO,CAAC;YACjBG,MAAM;YACNF,SAAS;YACTL,aACE;QACJ;IACF,EAAC;IAED,MAAaS,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACX;QAEjC,MAAMY,YAAY,MAAM,IAAI,CAACC,YAAY;QACzC,MAAMC,QAAQf,eAAea;QAE7B,wEAAwE;QACxE,qDAAqD;QACrD,MAAMG,YAAYtB,aAAamB;QAC/B,MAAMI,UAA2BD,YAC7BrB,+BAA+B;YAC7BuB,OAAOnB,SAASc;YAChBM,gBAAgBN,UAAUO,GAAG,EAAED;YAC/BE,MAAMN,QAAQ,YAAY;YAC1BC;QACF,KACAD,QACEnB,yBAAyBiB,aACzBhB,4BAA4BgB;QAElC,2EAA2E;QAC3E,2EAA2E;QAC3E,MAAMS,gBAAgB,IAAI,CAACC,YAAY,KAAK;YAAC,GAAGlB,KAAK;YAAEK,KAAK;QAAI,IAAIL;QACpE,MAAMP,YAAY;YAACO,OAAOiB;YAAeE,QAAQ,IAAI,CAACA,MAAM;QAAA,GAAGP;IACjE;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/devServer.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {\n extendViteConfigWithUserConfig,\n getViteConfig,\n writeSanityRuntime,\n} from '@sanity/cli-build/_internal/build'\nimport {\n getAppEnvironmentVariables,\n getStudioEnvironmentVariables,\n} from '@sanity/cli-build/_internal/env'\nimport {CliConfig, getCliTelemetry, type UserViteConfig} from '@sanity/cli-core'\nimport {type WorkbenchExposes} from '@sanity/workbench-cli/build'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport {type FSWatcher} from 'chokidar'\nimport {createServer, type InlineConfig, type ViteDevServer} from 'vite'\n\nimport {serverDebug} from './serverDebug.js'\nimport {sanityTypegenPlugin} from './vite/plugin-typegen.js'\n\nconst debug = serverDebug.extend('dev')\n\nexport interface DevServerOptions {\n basePath: string\n cwd: string\n httpPort: number\n\n reactCompiler: ReactCompilerConfig | undefined\n reactStrictMode: boolean | undefined\n\n staticPath: string\n\n appTitle?: string\n /** Enable Vite's experimental bundled dev mode (`experimental.bundledDev`). */\n bundledDev?: boolean\n entry?: string\n exposes?: WorkbenchExposes\n httpHost?: string\n isApp?: boolean\n isWorkbenchApp?: boolean\n projectName?: string\n schemaExtraction?: CliConfig['schemaExtraction']\n typegen?: CliConfig['typegen']\n vite?: UserViteConfig\n /** The workbench app's bus identity (`__SANITY_APP_ID__`). */\n workbenchAppId?: string\n}\n\ninterface DevServer {\n close(): Promise<void>\n server: ViteDevServer\n\n watcher?: FSWatcher\n}\n\nexport async function startDevServer(options: DevServerOptions): Promise<DevServer> {\n const {\n appTitle,\n basePath,\n bundledDev,\n cwd,\n entry,\n exposes,\n httpHost,\n httpPort,\n isApp,\n isWorkbenchApp,\n reactCompiler,\n reactStrictMode,\n schemaExtraction,\n typegen,\n vite: extendViteConfig,\n workbenchAppId,\n } = options\n\n debug('Writing Sanity runtime files')\n const {entries, watcher} = await writeSanityRuntime({\n appTitle,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n reactStrictMode,\n watch: true,\n })\n\n debug('Resolving vite config')\n const mode = 'development'\n\n function getEnvironmentVariables() {\n return isApp\n ? getAppEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n : getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n }\n\n let viteConfig: InlineConfig = await getViteConfig({\n additionalPlugins: [\n // Add typegen when enabled\n ...(typegen?.enabled\n ? [\n sanityTypegenPlugin({\n config: typegen,\n telemetryLogger: getCliTelemetry(),\n workDir: cwd,\n }),\n ]\n : []),\n ],\n basePath,\n cwd,\n entries,\n exposes,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n mode: 'development',\n reactCompiler,\n schemaExtraction,\n server: {host: httpHost, port: httpPort},\n workbenchAppId,\n })\n\n // Opt into Vite's experimental bundled dev mode. Set before the user-config\n // extension below so a `vite` override in sanity.cli.ts still has final say.\n //\n // Bundled mode bundles the app up front from an HTML entry, defaulting to\n // `<root>/index.html`. Sanity has no such file — it serves a virtual document\n // rewritten to `.sanity/runtime/index.html` — so point the bundler at the real\n // runtime HTML, otherwise the build fails with UNRESOLVED_ENTRY.\n if (bundledDev) {\n viteConfig = {\n ...viteConfig,\n build: {\n ...viteConfig.build,\n rolldownOptions: {\n ...viteConfig.build?.rolldownOptions,\n input: path.join(cwd, '.sanity', 'runtime', 'index.html'),\n },\n },\n experimental: {...viteConfig.experimental, bundledDev: true},\n }\n }\n\n // Extend Vite configuration with user-provided config\n if (extendViteConfig) {\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'serve', mode},\n viteConfig,\n extendViteConfig,\n )\n }\n\n debug('Creating vite server')\n const server = await createServer(viteConfig)\n\n debug('Listening on specified port')\n await server.listen()\n\n return {\n close: async () => {\n if (watcher) {\n await watcher.close()\n }\n await server.close()\n },\n server,\n watcher,\n }\n}\n"],"names":["path","extendViteConfigWithUserConfig","getViteConfig","writeSanityRuntime","getAppEnvironmentVariables","getStudioEnvironmentVariables","getCliTelemetry","createServer","serverDebug","sanityTypegenPlugin","debug","extend","startDevServer","options","appTitle","basePath","bundledDev","cwd","entry","exposes","httpHost","httpPort","isApp","isWorkbenchApp","reactCompiler","reactStrictMode","schemaExtraction","typegen","vite","extendViteConfig","workbenchAppId","entries","watcher","watch","mode","getEnvironmentVariables","jsonEncode","prefix","viteConfig","additionalPlugins","enabled","config","telemetryLogger","workDir","server","host","port","build","rolldownOptions","input","join","experimental","command","listen","close"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAE5B,SACEC,8BAA8B,EAC9BC,aAAa,EACbC,kBAAkB,QACb,oCAAmC;AAC1C,SACEC,0BAA0B,EAC1BC,6BAA6B,QACxB,kCAAiC;AACxC,SAAmBC,eAAe,QAA4B,mBAAkB;AAIhF,SAAQC,YAAY,QAA8C,OAAM;AAExE,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D,MAAMC,QAAQF,YAAYG,MAAM,CAAC;AAmCjC,OAAO,eAAeC,eAAeC,OAAyB;IAC5D,MAAM,EACJC,QAAQ,EACRC,QAAQ,EACRC,UAAU,EACVC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,QAAQ,EACRC,QAAQ,EACRC,KAAK,EACLC,cAAc,EACdC,aAAa,EACbC,eAAe,EACfC,gBAAgB,EAChBC,OAAO,EACPC,MAAMC,gBAAgB,EACtBC,cAAc,EACf,GAAGjB;IAEJH,MAAM;IACN,MAAM,EAACqB,OAAO,EAAEC,OAAO,EAAC,GAAG,MAAM7B,mBAAmB;QAClDW;QACAC;QACAE;QACAC;QACAI;QACAC;QACAE;QACAQ,OAAO;IACT;IAEAvB,MAAM;IACN,MAAMwB,OAAO;IAEb,SAASC;QACP,OAAOb,QACHlB,2BAA2B;YAACgC,YAAY;YAAMC,QAAQ;QAAc,KACpEhC,8BAA8B;YAAC+B,YAAY;YAAMC,QAAQ;QAAc;IAC7E;IAEA,IAAIC,aAA2B,MAAMpC,cAAc;QACjDqC,mBAAmB;YACjB,2BAA2B;eACvBZ,SAASa,UACT;gBACE/B,oBAAoB;oBAClBgC,QAAQd;oBACRe,iBAAiBpC;oBACjBqC,SAAS1B;gBACX;aACD,GACD,EAAE;SACP;QACDF;QACAE;QACAc;QACAZ;QACAgB;QACAb;QACAC;QACAW,MAAM;QACNV;QACAE;QACAkB,QAAQ;YAACC,MAAMzB;YAAU0B,MAAMzB;QAAQ;QACvCS;IACF;IAEA,4EAA4E;IAC5E,6EAA6E;IAC7E,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,+EAA+E;IAC/E,iEAAiE;IACjE,IAAId,YAAY;QACdsB,aAAa;YACX,GAAGA,UAAU;YACbS,OAAO;gBACL,GAAGT,WAAWS,KAAK;gBACnBC,iBAAiB;oBACf,GAAGV,WAAWS,KAAK,EAAEC,eAAe;oBACpCC,OAAOjD,KAAKkD,IAAI,CAACjC,KAAK,WAAW,WAAW;gBAC9C;YACF;YACAkC,cAAc;gBAAC,GAAGb,WAAWa,YAAY;gBAAEnC,YAAY;YAAI;QAC7D;IACF;IAEA,sDAAsD;IACtD,IAAIa,kBAAkB;QACpBS,aAAa,MAAMrC,+BACjB;YAACmD,SAAS;YAASlB;QAAI,GACvBI,YACAT;IAEJ;IAEAnB,MAAM;IACN,MAAMkC,SAAS,MAAMrC,aAAa+B;IAElC5B,MAAM;IACN,MAAMkC,OAAOS,MAAM;IAEnB,OAAO;QACLC,OAAO;YACL,IAAItB,SAAS;gBACX,MAAMA,QAAQsB,KAAK;YACrB;YACA,MAAMV,OAAOU,KAAK;QACpB;QACAV;QACAZ;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/server/devServer.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {\n extendViteConfigWithUserConfig,\n getViteConfig,\n writeSanityRuntime,\n} from '@sanity/cli-build/_internal/build'\nimport {\n getAppEnvironmentVariables,\n getStudioEnvironmentVariables,\n} from '@sanity/cli-build/_internal/env'\nimport {CliConfig, getCliTelemetry, type UserViteConfig} from '@sanity/cli-core'\nimport {type WorkbenchExposes} from '@sanity/workbench-cli/build'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport {type FSWatcher} from 'chokidar'\nimport {createServer, type InlineConfig, type ViteDevServer} from 'vite'\n\nimport {serverDebug} from './serverDebug.js'\nimport {sanityTypegenPlugin} from './vite/plugin-typegen.js'\n\nconst debug = serverDebug.extend('dev')\n\nexport interface DevServerOptions {\n basePath: string\n cwd: string\n httpPort: number\n\n reactCompiler: boolean | ReactCompilerConfig | undefined\n reactStrictMode: boolean | undefined\n\n staticPath: string\n\n appTitle?: string\n /** Enable Vite's experimental bundled dev mode (`experimental.bundledDev`). */\n bundledDev?: boolean\n entry?: string\n exposes?: WorkbenchExposes\n httpHost?: string\n isApp?: boolean\n isWorkbenchApp?: boolean\n projectName?: string\n schemaExtraction?: CliConfig['schemaExtraction']\n typegen?: CliConfig['typegen']\n vite?: UserViteConfig\n /** The workbench app's bus identity (`__SANITY_APP_ID__`). */\n workbenchAppId?: string\n}\n\ninterface DevServer {\n close(): Promise<void>\n server: ViteDevServer\n\n watcher?: FSWatcher\n}\n\nexport async function startDevServer(options: DevServerOptions): Promise<DevServer> {\n const {\n appTitle,\n basePath,\n bundledDev,\n cwd,\n entry,\n exposes,\n httpHost,\n httpPort,\n isApp,\n isWorkbenchApp,\n reactCompiler,\n reactStrictMode,\n schemaExtraction,\n typegen,\n vite: extendViteConfig,\n workbenchAppId,\n } = options\n\n debug('Writing Sanity runtime files')\n const {entries, watcher} = await writeSanityRuntime({\n appTitle,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n reactStrictMode,\n watch: true,\n })\n\n debug('Resolving vite config')\n const mode = 'development'\n\n function getEnvironmentVariables() {\n return isApp\n ? getAppEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n : getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n }\n\n let viteConfig: InlineConfig = await getViteConfig({\n additionalPlugins: [\n // Add typegen when enabled\n ...(typegen?.enabled\n ? [\n sanityTypegenPlugin({\n config: typegen,\n telemetryLogger: getCliTelemetry(),\n workDir: cwd,\n }),\n ]\n : []),\n ],\n basePath,\n cwd,\n entries,\n exposes,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n mode: 'development',\n reactCompiler,\n schemaExtraction,\n server: {host: httpHost, port: httpPort},\n workbenchAppId,\n })\n\n // Opt into Vite's experimental bundled dev mode. Set before the user-config\n // extension below so a `vite` override in sanity.cli.ts still has final say.\n //\n // Bundled mode bundles the app up front from an HTML entry, defaulting to\n // `<root>/index.html`. Sanity has no such file — it serves a virtual document\n // rewritten to `.sanity/runtime/index.html` — so point the bundler at the real\n // runtime HTML, otherwise the build fails with UNRESOLVED_ENTRY.\n if (bundledDev) {\n viteConfig = {\n ...viteConfig,\n build: {\n ...viteConfig.build,\n rolldownOptions: {\n ...viteConfig.build?.rolldownOptions,\n input: path.join(cwd, '.sanity', 'runtime', 'index.html'),\n },\n },\n experimental: {...viteConfig.experimental, bundledDev: true},\n }\n }\n\n // Extend Vite configuration with user-provided config\n if (extendViteConfig) {\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'serve', mode},\n viteConfig,\n extendViteConfig,\n )\n }\n\n debug('Creating vite server')\n const server = await createServer(viteConfig)\n\n debug('Listening on specified port')\n await server.listen()\n\n return {\n close: async () => {\n if (watcher) {\n await watcher.close()\n }\n await server.close()\n },\n server,\n watcher,\n }\n}\n"],"names":["path","extendViteConfigWithUserConfig","getViteConfig","writeSanityRuntime","getAppEnvironmentVariables","getStudioEnvironmentVariables","getCliTelemetry","createServer","serverDebug","sanityTypegenPlugin","debug","extend","startDevServer","options","appTitle","basePath","bundledDev","cwd","entry","exposes","httpHost","httpPort","isApp","isWorkbenchApp","reactCompiler","reactStrictMode","schemaExtraction","typegen","vite","extendViteConfig","workbenchAppId","entries","watcher","watch","mode","getEnvironmentVariables","jsonEncode","prefix","viteConfig","additionalPlugins","enabled","config","telemetryLogger","workDir","server","host","port","build","rolldownOptions","input","join","experimental","command","listen","close"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAE5B,SACEC,8BAA8B,EAC9BC,aAAa,EACbC,kBAAkB,QACb,oCAAmC;AAC1C,SACEC,0BAA0B,EAC1BC,6BAA6B,QACxB,kCAAiC;AACxC,SAAmBC,eAAe,QAA4B,mBAAkB;AAIhF,SAAQC,YAAY,QAA8C,OAAM;AAExE,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D,MAAMC,QAAQF,YAAYG,MAAM,CAAC;AAmCjC,OAAO,eAAeC,eAAeC,OAAyB;IAC5D,MAAM,EACJC,QAAQ,EACRC,QAAQ,EACRC,UAAU,EACVC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,QAAQ,EACRC,QAAQ,EACRC,KAAK,EACLC,cAAc,EACdC,aAAa,EACbC,eAAe,EACfC,gBAAgB,EAChBC,OAAO,EACPC,MAAMC,gBAAgB,EACtBC,cAAc,EACf,GAAGjB;IAEJH,MAAM;IACN,MAAM,EAACqB,OAAO,EAAEC,OAAO,EAAC,GAAG,MAAM7B,mBAAmB;QAClDW;QACAC;QACAE;QACAC;QACAI;QACAC;QACAE;QACAQ,OAAO;IACT;IAEAvB,MAAM;IACN,MAAMwB,OAAO;IAEb,SAASC;QACP,OAAOb,QACHlB,2BAA2B;YAACgC,YAAY;YAAMC,QAAQ;QAAc,KACpEhC,8BAA8B;YAAC+B,YAAY;YAAMC,QAAQ;QAAc;IAC7E;IAEA,IAAIC,aAA2B,MAAMpC,cAAc;QACjDqC,mBAAmB;YACjB,2BAA2B;eACvBZ,SAASa,UACT;gBACE/B,oBAAoB;oBAClBgC,QAAQd;oBACRe,iBAAiBpC;oBACjBqC,SAAS1B;gBACX;aACD,GACD,EAAE;SACP;QACDF;QACAE;QACAc;QACAZ;QACAgB;QACAb;QACAC;QACAW,MAAM;QACNV;QACAE;QACAkB,QAAQ;YAACC,MAAMzB;YAAU0B,MAAMzB;QAAQ;QACvCS;IACF;IAEA,4EAA4E;IAC5E,6EAA6E;IAC7E,EAAE;IACF,0EAA0E;IAC1E,8EAA8E;IAC9E,+EAA+E;IAC/E,iEAAiE;IACjE,IAAId,YAAY;QACdsB,aAAa;YACX,GAAGA,UAAU;YACbS,OAAO;gBACL,GAAGT,WAAWS,KAAK;gBACnBC,iBAAiB;oBACf,GAAGV,WAAWS,KAAK,EAAEC,eAAe;oBACpCC,OAAOjD,KAAKkD,IAAI,CAACjC,KAAK,WAAW,WAAW;gBAC9C;YACF;YACAkC,cAAc;gBAAC,GAAGb,WAAWa,YAAY;gBAAEnC,YAAY;YAAI;QAC7D;IACF;IAEA,sDAAsD;IACtD,IAAIa,kBAAkB;QACpBS,aAAa,MAAMrC,+BACjB;YAACmD,SAAS;YAASlB;QAAI,GACvBI,YACAT;IAEJ;IAEAnB,MAAM;IACN,MAAMkC,SAAS,MAAMrC,aAAa+B;IAElC5B,MAAM;IACN,MAAMkC,OAAOS,MAAM;IAEnB,OAAO;QACLC,OAAO;YACL,IAAItB,SAAS;gBACX,MAAMA,QAAQsB,KAAK;YACrB;YACA,MAAMV,OAAOU,KAAK;QACpB;QACAV;QACAZ;IACF;AACF"}
@@ -0,0 +1,83 @@
1
+ import { debug as cliDebug } from '@sanity/cli-core';
2
+ import { getErrorMessage } from '@sanity/cli-core/errors';
3
+ import { logSymbols } from '@sanity/cli-core/ux';
4
+ export function createFailFastReporter(output) {
5
+ return {
6
+ report (check) {
7
+ // Fixes surface in both modes: appended after the message here, and in the
8
+ // dry-run report, so the problem and its fix never drift apart.
9
+ const text = check.solution ? `${check.message}: ${check.solution}` : check.message;
10
+ if (check.status === 'fail') {
11
+ output.error(text, {
12
+ exit: check.exitCode ?? 1
13
+ });
14
+ } else if (check.status === 'warn') {
15
+ output.warn(text);
16
+ }
17
+ }
18
+ };
19
+ }
20
+ export function createCollectingReporter() {
21
+ const results = [];
22
+ return {
23
+ report (check) {
24
+ results.push(check);
25
+ },
26
+ results
27
+ };
28
+ }
29
+ /**
30
+ * Runs a fallible step and turns a throw into a `fail` check. In a real run
31
+ * that fail exits (aborting the sequence); in a dry run it's recorded and
32
+ * `null` comes back so the caller can skip the rest of the step. `name` labels
33
+ * the step in debug logs.
34
+ */ export async function runStep(reporter, step) {
35
+ const { debug = cliDebug, formatError = getErrorMessage, name, solution, work } = step;
36
+ try {
37
+ return await work();
38
+ } catch (err) {
39
+ debug(`${name} step failed`, err);
40
+ reporter.report({
41
+ message: formatError(err),
42
+ solution,
43
+ status: 'fail'
44
+ });
45
+ return null;
46
+ }
47
+ }
48
+ export function checkStatusIcon(status) {
49
+ switch(status){
50
+ case 'fail':
51
+ {
52
+ return logSymbols.error;
53
+ }
54
+ case 'skip':
55
+ {
56
+ return logSymbols.info;
57
+ }
58
+ case 'warn':
59
+ {
60
+ return logSymbols.warning;
61
+ }
62
+ default:
63
+ {
64
+ return logSymbols.success;
65
+ }
66
+ }
67
+ }
68
+ /**
69
+ * Indents continuation lines of a multi-line check message past the status
70
+ * icon so its items nest under the heading.
71
+ */ export function nestLines(text) {
72
+ return text.replaceAll('\n', '\n ');
73
+ }
74
+ /** Renders problem/warning checks under a title, each with its fix appended. */ export function renderIssues(output, title, checks) {
75
+ if (checks.length === 0) return;
76
+ output.log(`\n${title}`);
77
+ for (const check of checks){
78
+ const fix = check.solution ? `: ${check.solution}` : '';
79
+ output.log(nestLines(` ${checkStatusIcon(check.status)} ${check.message}${fix}`));
80
+ }
81
+ }
82
+
83
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/checks.ts"],"sourcesContent":["import {debug as cliDebug, type Output} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nexport type CheckStatus = 'fail' | 'pass' | 'skip' | 'warn'\n\nexport interface Check {\n message: string\n status: CheckStatus\n\n /** Exit code a real run uses when this check fails; defaults to 1 */\n exitCode?: number\n /** Actionable fix, shown under a failing or warning check */\n solution?: string\n}\n\n/**\n * Where a command's steps send their check outcomes — and the only place the\n * run mode lives. A real run fails fast: a `fail` prints and exits immediately,\n * which aborts the sequence. A dry run collects every outcome and never exits.\n * Steps just call `report`; they never know which mode is running.\n */\nexport interface CheckReporter<TCheck extends Check = Check> {\n report(check: TCheck): void\n}\n\nexport function createFailFastReporter(output: Output): CheckReporter {\n return {\n report(check) {\n // Fixes surface in both modes: appended after the message here, and in the\n // dry-run report, so the problem and its fix never drift apart.\n const text = check.solution ? `${check.message}: ${check.solution}` : check.message\n if (check.status === 'fail') {\n output.error(text, {exit: check.exitCode ?? 1})\n } else if (check.status === 'warn') {\n output.warn(text)\n }\n },\n }\n}\n\nexport function createCollectingReporter<TCheck extends Check = Check>(): CheckReporter<TCheck> & {\n results: TCheck[]\n} {\n const results: TCheck[] = []\n return {\n report(check) {\n results.push(check)\n },\n results,\n }\n}\n\n/**\n * Runs a fallible step and turns a throw into a `fail` check. In a real run\n * that fail exits (aborting the sequence); in a dry run it's recorded and\n * `null` comes back so the caller can skip the rest of the step. `name` labels\n * the step in debug logs.\n */\nexport async function runStep<T>(\n reporter: CheckReporter,\n step: {\n debug?: (message: string, error: unknown) => void\n formatError?: (error: unknown) => string\n\n name: string\n solution?: string\n work: () => Promise<T>\n },\n): Promise<T | null> {\n const {debug = cliDebug, formatError = getErrorMessage, name, solution, work} = step\n try {\n return await work()\n } catch (err) {\n debug(`${name} step failed`, err)\n reporter.report({message: formatError(err), solution, status: 'fail'})\n return null\n }\n}\n\nexport function checkStatusIcon(status: CheckStatus): string {\n switch (status) {\n case 'fail': {\n return logSymbols.error\n }\n case 'skip': {\n return logSymbols.info\n }\n case 'warn': {\n return logSymbols.warning\n }\n default: {\n return logSymbols.success\n }\n }\n}\n\n/**\n * Indents continuation lines of a multi-line check message past the status\n * icon so its items nest under the heading.\n */\nexport function nestLines(text: string): string {\n return text.replaceAll('\\n', '\\n ')\n}\n\n/** Renders problem/warning checks under a title, each with its fix appended. */\nexport function renderIssues(output: Output, title: string, checks: Check[]): void {\n if (checks.length === 0) return\n\n output.log(`\\n${title}`)\n for (const check of checks) {\n const fix = check.solution ? `: ${check.solution}` : ''\n output.log(nestLines(` ${checkStatusIcon(check.status)} ${check.message}${fix}`))\n }\n}\n"],"names":["debug","cliDebug","getErrorMessage","logSymbols","createFailFastReporter","output","report","check","text","solution","message","status","error","exit","exitCode","warn","createCollectingReporter","results","push","runStep","reporter","step","formatError","name","work","err","checkStatusIcon","info","warning","success","nestLines","replaceAll","renderIssues","title","checks","length","log","fix"],"mappings":"AAAA,SAAQA,SAASC,QAAQ,QAAoB,mBAAkB;AAC/D,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,UAAU,QAAO,sBAAqB;AAwB9C,OAAO,SAASC,uBAAuBC,MAAc;IACnD,OAAO;QACLC,QAAOC,KAAK;YACV,2EAA2E;YAC3E,gEAAgE;YAChE,MAAMC,OAAOD,MAAME,QAAQ,GAAG,GAAGF,MAAMG,OAAO,CAAC,EAAE,EAAEH,MAAME,QAAQ,EAAE,GAAGF,MAAMG,OAAO;YACnF,IAAIH,MAAMI,MAAM,KAAK,QAAQ;gBAC3BN,OAAOO,KAAK,CAACJ,MAAM;oBAACK,MAAMN,MAAMO,QAAQ,IAAI;gBAAC;YAC/C,OAAO,IAAIP,MAAMI,MAAM,KAAK,QAAQ;gBAClCN,OAAOU,IAAI,CAACP;YACd;QACF;IACF;AACF;AAEA,OAAO,SAASQ;IAGd,MAAMC,UAAoB,EAAE;IAC5B,OAAO;QACLX,QAAOC,KAAK;YACVU,QAAQC,IAAI,CAACX;QACf;QACAU;IACF;AACF;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,QACpBC,QAAuB,EACvBC,IAOC;IAED,MAAM,EAACrB,QAAQC,QAAQ,EAAEqB,cAAcpB,eAAe,EAAEqB,IAAI,EAAEd,QAAQ,EAAEe,IAAI,EAAC,GAAGH;IAChF,IAAI;QACF,OAAO,MAAMG;IACf,EAAE,OAAOC,KAAK;QACZzB,MAAM,GAAGuB,KAAK,YAAY,CAAC,EAAEE;QAC7BL,SAASd,MAAM,CAAC;YAACI,SAASY,YAAYG;YAAMhB;YAAUE,QAAQ;QAAM;QACpE,OAAO;IACT;AACF;AAEA,OAAO,SAASe,gBAAgBf,MAAmB;IACjD,OAAQA;QACN,KAAK;YAAQ;gBACX,OAAOR,WAAWS,KAAK;YACzB;QACA,KAAK;YAAQ;gBACX,OAAOT,WAAWwB,IAAI;YACxB;QACA,KAAK;YAAQ;gBACX,OAAOxB,WAAWyB,OAAO;YAC3B;QACA;YAAS;gBACP,OAAOzB,WAAW0B,OAAO;YAC3B;IACF;AACF;AAEA;;;CAGC,GACD,OAAO,SAASC,UAAUtB,IAAY;IACpC,OAAOA,KAAKuB,UAAU,CAAC,MAAM;AAC/B;AAEA,8EAA8E,GAC9E,OAAO,SAASC,aAAa3B,MAAc,EAAE4B,KAAa,EAAEC,MAAe;IACzE,IAAIA,OAAOC,MAAM,KAAK,GAAG;IAEzB9B,OAAO+B,GAAG,CAAC,CAAC,EAAE,EAAEH,OAAO;IACvB,KAAK,MAAM1B,SAAS2B,OAAQ;QAC1B,MAAMG,MAAM9B,MAAME,QAAQ,GAAG,CAAC,EAAE,EAAEF,MAAME,QAAQ,EAAE,GAAG;QACrDJ,OAAO+B,GAAG,CAACN,UAAU,CAAC,EAAE,EAAEJ,gBAAgBnB,MAAMI,MAAM,EAAE,CAAC,EAAEJ,MAAMG,OAAO,GAAG2B,KAAK;IAClF;AACF"}
@@ -0,0 +1,13 @@
1
+ import { format } from 'node:util';
2
+ /**
3
+ * An `Output` whose `log` writes to stderr, for `--json` runs where the payload
4
+ * owns stdout and progress logs must not corrupt it. Spinners are already on
5
+ * stderr.
6
+ */ export function toStderrOutput(output) {
7
+ return {
8
+ ...output,
9
+ log: (message = '', ...args)=>void process.stderr.write(`${format(message, ...args)}\n`)
10
+ };
11
+ }
12
+
13
+ //# sourceMappingURL=toStderrOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/toStderrOutput.ts"],"sourcesContent":["import {format} from 'node:util'\n\nimport {type Output} from '@sanity/cli-core'\n\n/**\n * An `Output` whose `log` writes to stderr, for `--json` runs where the payload\n * owns stdout and progress logs must not corrupt it. Spinners are already on\n * stderr.\n */\nexport function toStderrOutput(output: Output): Output {\n return {\n ...output,\n log: (message = '', ...args: unknown[]) =>\n void process.stderr.write(`${format(message, ...args)}\\n`),\n }\n}\n"],"names":["format","toStderrOutput","output","log","message","args","process","stderr","write"],"mappings":"AAAA,SAAQA,MAAM,QAAO,YAAW;AAIhC;;;;CAIC,GACD,OAAO,SAASC,eAAeC,MAAc;IAC3C,OAAO;QACL,GAAGA,MAAM;QACTC,KAAK,CAACC,UAAU,EAAE,EAAE,GAAGC,OACrB,KAAKC,QAAQC,MAAM,CAACC,KAAK,CAAC,GAAGR,OAAOI,YAAYC,MAAM,EAAE,CAAC;IAC7D;AACF"}
@@ -1011,7 +1011,34 @@
1011
1011
  "aliases": [],
1012
1012
  "args": {},
1013
1013
  "description": "Removes the deployed Sanity Studio/App from Sanity hosting",
1014
+ "examples": [
1015
+ {
1016
+ "command": "<%= config.bin %> <%= command.id %>",
1017
+ "description": "Undeploy the studio or application after confirming"
1018
+ },
1019
+ {
1020
+ "command": "<%= config.bin %> <%= command.id %> --dry-run",
1021
+ "description": "Report what would be undeployed without deleting anything"
1022
+ },
1023
+ {
1024
+ "command": "<%= config.bin %> <%= command.id %> --json --yes",
1025
+ "description": "Undeploy without prompting and report the result as JSON"
1026
+ }
1027
+ ],
1014
1028
  "flags": {
1029
+ "dry-run": {
1030
+ "description": "Report what would be undeployed without deleting anything",
1031
+ "name": "dry-run",
1032
+ "allowNo": false,
1033
+ "type": "boolean"
1034
+ },
1035
+ "json": {
1036
+ "char": "j",
1037
+ "description": "Output the result as JSON",
1038
+ "name": "json",
1039
+ "allowNo": false,
1040
+ "type": "boolean"
1041
+ },
1015
1042
  "yes": {
1016
1043
  "char": "y",
1017
1044
  "description": "Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults",
@@ -5169,5 +5196,5 @@
5169
5196
  ]
5170
5197
  }
5171
5198
  },
5172
- "version": "7.7.1"
5199
+ "version": "7.9.0"
5173
5200
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli",
3
- "version": "7.7.1",
3
+ "version": "7.9.0",
4
4
  "description": "Sanity CLI tool for managing Sanity projects and organizations",
5
5
  "keywords": [
6
6
  "cli",
@@ -118,9 +118,9 @@
118
118
  "which": "^6.0.1",
119
119
  "yaml": "^2.9.0",
120
120
  "zod": "^4.4.3",
121
- "@sanity/workbench-cli": "^1.2.0",
122
- "@sanity/cli-build": "^3.0.0",
123
- "@sanity/cli-core": "^2.2.1"
121
+ "@sanity/cli-build": "^4.1.0",
122
+ "@sanity/cli-core": "^2.4.0",
123
+ "@sanity/workbench-cli": "^1.4.0"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@eslint/compat": "^2.1.0",
@@ -144,7 +144,6 @@
144
144
  "@types/which": "^3.0.4",
145
145
  "@vitest/coverage-istanbul": "^4.1.9",
146
146
  "babel-plugin-react-compiler": "^1.0.0",
147
- "es-module-lexer": "^2.1.0",
148
147
  "eslint": "^10.4.1",
149
148
  "jsdom": "^29.1.1",
150
149
  "nock": "^14.0.15",
@@ -155,9 +154,9 @@
155
154
  "typescript": "^5.9.3",
156
155
  "vitest": "^4.1.9",
157
156
  "@repo/package.config": "0.0.1",
158
- "@repo/tsconfig": "3.70.0",
159
- "@sanity/cli-test": "3.0.1",
160
- "@sanity/eslint-config-cli": "1.1.2"
157
+ "@sanity/cli-test": "5.0.0",
158
+ "@sanity/eslint-config-cli": "1.1.2",
159
+ "@repo/tsconfig": "3.70.0"
161
160
  },
162
161
  "peerDependencies": {
163
162
  "babel-plugin-react-compiler": "*"
@@ -1,36 +0,0 @@
1
- import { getUserApplication } from '../../services/userApplications.js';
2
- import { getAppId } from '../../util/appId.js';
3
- import { determineIsApp } from '../../util/determineIsApp.js';
4
- import { NO_PROJECT_ID } from '../../util/errorMessages.js';
5
- export const NO_APP_ID = 'NO_APP_ID';
6
- export const NO_APP_ID_OR_STUDIO_HOST = 'NO_APP_ID_OR_STUDIO_HOST';
7
- // Used only in undeploy flow
8
- export async function getStudioOrAppUserApplication(options) {
9
- const { cliConfig } = options;
10
- const projectId = cliConfig.api?.projectId;
11
- const isApp = determineIsApp(cliConfig);
12
- if (isApp) {
13
- const appId = getAppId(cliConfig);
14
- if (!appId) {
15
- throw new Error(NO_APP_ID);
16
- }
17
- return getUserApplication({
18
- appId,
19
- isSdkApp: true
20
- });
21
- }
22
- if (!cliConfig.studioHost && !cliConfig.deployment?.appId) {
23
- throw new Error(NO_APP_ID_OR_STUDIO_HOST);
24
- }
25
- if (!projectId) {
26
- throw new Error(NO_PROJECT_ID);
27
- }
28
- return getUserApplication({
29
- appHost: cliConfig.studioHost,
30
- appId: cliConfig.deployment?.appId,
31
- isSdkApp: false,
32
- projectId
33
- });
34
- }
35
-
36
- //# sourceMappingURL=getStudioOrAppUserApplication.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/actions/undeploy/getStudioOrAppUserApplication.ts"],"sourcesContent":["import {type CliConfig, type Output} from '@sanity/cli-core'\n\nimport {getUserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {determineIsApp} from '../../util/determineIsApp.js'\nimport {NO_PROJECT_ID} from '../../util/errorMessages.js'\n\ninterface GetStudioOrAppUserApplicationOptions {\n cliConfig: CliConfig\n output: Output\n}\n\nexport const NO_APP_ID = 'NO_APP_ID'\nexport const NO_APP_ID_OR_STUDIO_HOST = 'NO_APP_ID_OR_STUDIO_HOST'\n\n// Used only in undeploy flow\nexport async function getStudioOrAppUserApplication(options: GetStudioOrAppUserApplicationOptions) {\n const {cliConfig} = options\n const projectId = cliConfig.api?.projectId\n const isApp = determineIsApp(cliConfig)\n\n if (isApp) {\n const appId = getAppId(cliConfig)\n if (!appId) {\n throw new Error(NO_APP_ID)\n }\n\n return getUserApplication({appId, isSdkApp: true})\n }\n\n if (!cliConfig.studioHost && !cliConfig.deployment?.appId) {\n throw new Error(NO_APP_ID_OR_STUDIO_HOST)\n }\n\n if (!projectId) {\n throw new Error(NO_PROJECT_ID)\n }\n\n return getUserApplication({\n appHost: cliConfig.studioHost,\n appId: cliConfig.deployment?.appId,\n isSdkApp: false,\n projectId,\n })\n}\n"],"names":["getUserApplication","getAppId","determineIsApp","NO_PROJECT_ID","NO_APP_ID","NO_APP_ID_OR_STUDIO_HOST","getStudioOrAppUserApplication","options","cliConfig","projectId","api","isApp","appId","Error","isSdkApp","studioHost","deployment","appHost"],"mappings":"AAEA,SAAQA,kBAAkB,QAAO,qCAAoC;AACrE,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,cAAc,QAAO,+BAA8B;AAC3D,SAAQC,aAAa,QAAO,8BAA6B;AAOzD,OAAO,MAAMC,YAAY,YAAW;AACpC,OAAO,MAAMC,2BAA2B,2BAA0B;AAElE,6BAA6B;AAC7B,OAAO,eAAeC,8BAA8BC,OAA6C;IAC/F,MAAM,EAACC,SAAS,EAAC,GAAGD;IACpB,MAAME,YAAYD,UAAUE,GAAG,EAAED;IACjC,MAAME,QAAQT,eAAeM;IAE7B,IAAIG,OAAO;QACT,MAAMC,QAAQX,SAASO;QACvB,IAAI,CAACI,OAAO;YACV,MAAM,IAAIC,MAAMT;QAClB;QAEA,OAAOJ,mBAAmB;YAACY;YAAOE,UAAU;QAAI;IAClD;IAEA,IAAI,CAACN,UAAUO,UAAU,IAAI,CAACP,UAAUQ,UAAU,EAAEJ,OAAO;QACzD,MAAM,IAAIC,MAAMR;IAClB;IAEA,IAAI,CAACI,WAAW;QACd,MAAM,IAAII,MAAMV;IAClB;IAEA,OAAOH,mBAAmB;QACxBiB,SAAST,UAAUO,UAAU;QAC7BH,OAAOJ,UAAUQ,UAAU,EAAEJ;QAC7BE,UAAU;QACVL;IACF;AACF"}
@@ -1,110 +0,0 @@
1
- import path from 'node:path';
2
- import { getModuleUrl } from '@sanity/cli-build/_internal/build';
3
- import { getLocalPackageVersion, readPackageJson } from '@sanity/cli-core';
4
- import { createRequester } from '@sanity/cli-core/request';
5
- import { coerce, eq, prerelease, parse as semverParse } from 'semver';
6
- const defaultRequester = createRequester({
7
- middleware: {
8
- httpErrors: false,
9
- promise: {
10
- onlyBody: false
11
- }
12
- }
13
- });
14
- /**
15
- * @internal
16
- *
17
- * Compares the versions of dependencies in the studio or app with their remote versions.
18
- *
19
- * This function reads the package.json file in the provided working directory, and compares the versions of the dependencies
20
- * specified in the `autoUpdatesImports` parameter with their remote versions. If the versions do not match, the dependency is
21
- * added to a list of failed dependencies, which is returned by the function.
22
- *
23
- * The failed dependencies are anything that does not strictly match the remote version.
24
- * This means that if a version is lower or greater by even a patch it will be marked as failed.
25
- *
26
- * @param packages - An array of packages with their name and version to compare against remote.
27
- * @param workDir - The path to the working directory containing the package.json file.
28
- * @param options - Optional configuration for version comparison.
29
- *
30
- * @returns A promise that resolves to an object containing `mismatched` (packages whose local and remote versions differ)
31
- * and `unresolvedPrerelease` (packages with prerelease versions that could not be resolved remotely).
32
- *
33
- * @throws Throws an error if the remote version of a non-prerelease package cannot be fetched, or if the local version
34
- * of a package cannot be parsed.
35
- */ export async function compareDependencyVersions(packages, workDir, { appId, requester = defaultRequester } = {}) {
36
- const manifest = await readPackageJson(path.join(workDir, 'package.json'), {
37
- skipSchemaValidation: true
38
- });
39
- const dependencies = {
40
- ...manifest?.dependencies,
41
- ...manifest?.devDependencies
42
- };
43
- const mismatched = [];
44
- const unresolvedPrerelease = [];
45
- for (const pkg of packages){
46
- // Skip packages that are not declared in the local package.json
47
- if (!dependencies[pkg.name]) {
48
- continue;
49
- }
50
- const resolvedVersion = await getRemoteResolvedVersion(getModuleUrl(pkg, {
51
- appId
52
- }), requester);
53
- if (resolvedVersion === null) {
54
- if (prerelease(pkg.version)) {
55
- unresolvedPrerelease.push({
56
- pkg: pkg.name,
57
- version: pkg.version
58
- });
59
- continue;
60
- }
61
- throw new Error(`Failed to resolve remote version for ${pkg.name}@${pkg.version}: package not found`);
62
- }
63
- const packageVersion = await getLocalPackageVersion(pkg.name, workDir);
64
- const manifestVersion = dependencies[pkg.name];
65
- const installed = coerce(packageVersion ? semverParse(packageVersion) : coerce(manifestVersion));
66
- if (!installed) {
67
- throw new Error(`Failed to parse installed version for ${pkg.name}`);
68
- }
69
- if (!eq(resolvedVersion, installed.version)) {
70
- mismatched.push({
71
- installed: installed.version,
72
- pkg: pkg.name,
73
- remote: resolvedVersion
74
- });
75
- }
76
- }
77
- return {
78
- mismatched,
79
- unresolvedPrerelease
80
- };
81
- }
82
- async function getRemoteResolvedVersion(url, request) {
83
- let response;
84
- try {
85
- response = await request({
86
- maxRedirects: 0,
87
- method: 'HEAD',
88
- url
89
- });
90
- } catch (err) {
91
- const message = err instanceof Error ? err.message : String(err);
92
- throw new Error(`Failed to fetch remote version for ${url}: ${message}`, {
93
- cause: err
94
- });
95
- }
96
- // 302 is expected, but lets also handle 2xx
97
- if (response.statusCode < 400) {
98
- const resolved = response.headers['x-resolved-version'];
99
- if (!resolved) {
100
- throw new Error(`Missing 'x-resolved-version' header on response from HEAD ${url}`);
101
- }
102
- return resolved;
103
- }
104
- if (response.statusCode === 404) {
105
- return null;
106
- }
107
- throw new Error(`Unexpected HTTP response: ${response.statusCode} ${response.statusMessage}`);
108
- }
109
-
110
- //# sourceMappingURL=compareDependencyVersions.js.map