@sanity/cli 7.10.0 → 7.11.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 (157) hide show
  1. package/README.md +31 -22
  2. package/dist/actions/auth/ensureAuthenticated.js +2 -0
  3. package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
  4. package/dist/actions/auth/login/loginInstructions.js +19 -0
  5. package/dist/actions/auth/login/loginInstructions.js.map +1 -0
  6. package/dist/actions/dataset/resolveDataset.js +7 -1
  7. package/dist/actions/dataset/resolveDataset.js.map +1 -1
  8. package/dist/actions/deploy/deployApp.js +17 -12
  9. package/dist/actions/deploy/deployApp.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +2 -0
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/graphql/resolveApiGeneration.js +9 -6
  13. package/dist/actions/graphql/resolveApiGeneration.js.map +1 -1
  14. package/dist/actions/init/initAction.js +23 -15
  15. package/dist/actions/init/initAction.js.map +1 -1
  16. package/dist/actions/manifest/extractCoreAppManifest.js +5 -3
  17. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  18. package/dist/actions/migration/constants.js +10 -0
  19. package/dist/actions/migration/constants.js.map +1 -0
  20. package/dist/actions/migration/ensureApiVersionFormat.js +16 -0
  21. package/dist/actions/migration/ensureApiVersionFormat.js.map +1 -0
  22. package/dist/actions/migration/fileExists.js +13 -0
  23. package/dist/actions/migration/fileExists.js.map +1 -0
  24. package/dist/actions/migration/prettyMutationFormatter.js +155 -0
  25. package/dist/actions/migration/prettyMutationFormatter.js.map +1 -0
  26. package/dist/actions/migration/resolveMigrationScript.js +75 -0
  27. package/dist/actions/migration/resolveMigrationScript.js.map +1 -0
  28. package/dist/actions/migration/resolveMigrations.js +50 -0
  29. package/dist/actions/migration/resolveMigrations.js.map +1 -0
  30. package/dist/actions/migration/templates/index.js +7 -0
  31. package/dist/actions/migration/templates/index.js.map +1 -0
  32. package/dist/actions/migration/templates/minimalAdvanced.js +21 -0
  33. package/dist/actions/migration/templates/minimalAdvanced.js.map +1 -0
  34. package/dist/actions/migration/templates/minimalSimple.js +61 -0
  35. package/dist/actions/migration/templates/minimalSimple.js.map +1 -0
  36. package/dist/actions/migration/templates/renameField.js +20 -0
  37. package/dist/actions/migration/templates/renameField.js.map +1 -0
  38. package/dist/actions/migration/templates/renameType.js +19 -0
  39. package/dist/actions/migration/templates/renameType.js.map +1 -0
  40. package/dist/actions/migration/templates/stringToPTE.js +32 -0
  41. package/dist/actions/migration/templates/stringToPTE.js.map +1 -0
  42. package/dist/actions/migration/tree.js +111 -0
  43. package/dist/actions/migration/tree.js.map +1 -0
  44. package/dist/actions/preview/previewAction.js +33 -1
  45. package/dist/actions/preview/previewAction.js.map +1 -1
  46. package/dist/actions/schema/listSchemas.js +6 -4
  47. package/dist/actions/schema/listSchemas.js.map +1 -1
  48. package/dist/actions/tokens/validateRole.js +2 -1
  49. package/dist/actions/tokens/validateRole.js.map +1 -1
  50. package/dist/actions/undeploy/runUndeploy.js +13 -4
  51. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  52. package/dist/commands/backups/disable.js +5 -1
  53. package/dist/commands/backups/disable.js.map +1 -1
  54. package/dist/commands/backups/download.js +30 -6
  55. package/dist/commands/backups/download.js.map +1 -1
  56. package/dist/commands/backups/enable.js +5 -1
  57. package/dist/commands/backups/enable.js.map +1 -1
  58. package/dist/commands/backups/list.js +5 -1
  59. package/dist/commands/backups/list.js.map +1 -1
  60. package/dist/commands/cors/add.js +15 -7
  61. package/dist/commands/cors/add.js.map +1 -1
  62. package/dist/commands/cors/delete.js +6 -1
  63. package/dist/commands/cors/delete.js.map +1 -1
  64. package/dist/commands/datasets/alias/create.js +25 -18
  65. package/dist/commands/datasets/alias/create.js.map +1 -1
  66. package/dist/commands/datasets/alias/delete.js +15 -8
  67. package/dist/commands/datasets/alias/delete.js.map +1 -1
  68. package/dist/commands/datasets/alias/link.js +39 -17
  69. package/dist/commands/datasets/alias/link.js.map +1 -1
  70. package/dist/commands/datasets/alias/unlink.js +23 -2
  71. package/dist/commands/datasets/alias/unlink.js.map +1 -1
  72. package/dist/commands/datasets/copy.js +18 -2
  73. package/dist/commands/datasets/copy.js.map +1 -1
  74. package/dist/commands/datasets/create.js +8 -2
  75. package/dist/commands/datasets/create.js.map +1 -1
  76. package/dist/commands/datasets/delete.js +14 -17
  77. package/dist/commands/datasets/delete.js.map +1 -1
  78. package/dist/commands/datasets/embeddings/disable.js +3 -0
  79. package/dist/commands/datasets/embeddings/disable.js.map +1 -1
  80. package/dist/commands/datasets/embeddings/enable.js +5 -2
  81. package/dist/commands/datasets/embeddings/enable.js.map +1 -1
  82. package/dist/commands/datasets/embeddings/status.js +3 -0
  83. package/dist/commands/datasets/embeddings/status.js.map +1 -1
  84. package/dist/commands/datasets/export.js +27 -15
  85. package/dist/commands/datasets/export.js.map +1 -1
  86. package/dist/commands/datasets/import.js +3 -3
  87. package/dist/commands/datasets/import.js.map +1 -1
  88. package/dist/commands/datasets/visibility/get.js +2 -2
  89. package/dist/commands/datasets/visibility/get.js.map +1 -1
  90. package/dist/commands/datasets/visibility/set.js +2 -2
  91. package/dist/commands/datasets/visibility/set.js.map +1 -1
  92. package/dist/commands/docs/read.js +3 -3
  93. package/dist/commands/docs/read.js.map +1 -1
  94. package/dist/commands/documents/create.js +18 -13
  95. package/dist/commands/documents/create.js.map +1 -1
  96. package/dist/commands/documents/delete.js +3 -3
  97. package/dist/commands/documents/delete.js.map +1 -1
  98. package/dist/commands/documents/get.js +3 -3
  99. package/dist/commands/documents/get.js.map +1 -1
  100. package/dist/commands/documents/query.js +3 -3
  101. package/dist/commands/documents/query.js.map +1 -1
  102. package/dist/commands/documents/validate.js +29 -26
  103. package/dist/commands/documents/validate.js.map +1 -1
  104. package/dist/commands/graphql/deploy.js +20 -16
  105. package/dist/commands/graphql/deploy.js.map +1 -1
  106. package/dist/commands/graphql/undeploy.js +15 -18
  107. package/dist/commands/graphql/undeploy.js.map +1 -1
  108. package/dist/commands/hooks/delete.js +2 -2
  109. package/dist/commands/hooks/delete.js.map +1 -1
  110. package/dist/commands/hooks/logs.js +2 -2
  111. package/dist/commands/hooks/logs.js.map +1 -1
  112. package/dist/commands/login.js +2 -1
  113. package/dist/commands/login.js.map +1 -1
  114. package/dist/commands/media/create-aspect.js +20 -8
  115. package/dist/commands/media/create-aspect.js.map +1 -1
  116. package/dist/commands/media/delete-aspect.js +31 -16
  117. package/dist/commands/media/delete-aspect.js.map +1 -1
  118. package/dist/commands/media/deploy-aspect.js +10 -5
  119. package/dist/commands/media/deploy-aspect.js.map +1 -1
  120. package/dist/commands/media/export.js +9 -4
  121. package/dist/commands/media/export.js.map +1 -1
  122. package/dist/commands/media/import.js +6 -1
  123. package/dist/commands/media/import.js.map +1 -1
  124. package/dist/commands/migrations/create.js +150 -0
  125. package/dist/commands/migrations/create.js.map +1 -0
  126. package/dist/commands/migrations/list.js +64 -0
  127. package/dist/commands/migrations/list.js.map +1 -0
  128. package/dist/commands/migrations/run.js +306 -0
  129. package/dist/commands/migrations/run.js.map +1 -0
  130. package/dist/commands/preview.js +1 -0
  131. package/dist/commands/preview.js.map +1 -1
  132. package/dist/commands/projects/create.js +2 -1
  133. package/dist/commands/projects/create.js.map +1 -1
  134. package/dist/commands/schemas/delete.js +23 -2
  135. package/dist/commands/schemas/delete.js.map +1 -1
  136. package/dist/commands/schemas/deploy.js +6 -4
  137. package/dist/commands/schemas/deploy.js.map +1 -1
  138. package/dist/commands/schemas/extract.js +22 -1
  139. package/dist/commands/schemas/extract.js.map +1 -1
  140. package/dist/commands/schemas/list.js +8 -8
  141. package/dist/commands/schemas/list.js.map +1 -1
  142. package/dist/commands/tokens/{add.js → create.js} +25 -18
  143. package/dist/commands/tokens/create.js.map +1 -0
  144. package/dist/commands/tokens/delete.js +41 -23
  145. package/dist/commands/tokens/delete.js.map +1 -1
  146. package/dist/commands/undeploy.js +2 -7
  147. package/dist/commands/undeploy.js.map +1 -1
  148. package/dist/commands/users/invite.js +25 -3
  149. package/dist/commands/users/invite.js.map +1 -1
  150. package/dist/topicAliases.js +3 -0
  151. package/dist/topicAliases.js.map +1 -1
  152. package/dist/util/formatCliErrorMessages.js +5 -0
  153. package/dist/util/formatCliErrorMessages.js.map +1 -0
  154. package/oclif.config.js +5 -1
  155. package/oclif.manifest.json +326 -121
  156. package/package.json +7 -7
  157. package/dist/commands/tokens/add.js.map +0 -1
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { styleText } from 'node:util';
4
4
  import { Args, Flags } from '@oclif/core';
5
- import { SanityCommand, subdebug } from '@sanity/cli-core';
5
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
6
6
  import { confirm, logSymbols } from '@sanity/cli-core/ux';
7
7
  import { oneline } from 'oneline';
8
8
  import { filterAndValidateOrigin } from '../../actions/cors/filterAndValidateOrigin.js';
@@ -46,6 +46,10 @@ export class Add extends SanityCommand {
46
46
  default: undefined,
47
47
  description: 'Allow credentials (token/cookie) to be sent from this origin',
48
48
  required: false
49
+ }),
50
+ yes: Flags.boolean({
51
+ char: 'y',
52
+ description: 'Confirm risky wildcard origins without prompting'
49
53
  })
50
54
  };
51
55
  async run() {
@@ -74,14 +78,18 @@ export class Add extends SanityCommand {
74
78
  const filteredOrigin = await filterAndValidateOrigin(origin, this.output);
75
79
  const hasWildcard = origin.includes('*');
76
80
  if (hasWildcard) {
77
- const confirmed = await this.promptForWildcardConfirmation(origin);
78
- if (!confirmed) {
79
- this.error('Operation cancelled', {
80
- exit: 1
81
+ if (this.isUnattended() && !flags.yes) {
82
+ this.error('Wildcard origins require confirmation. Pass `--yes` to continue.', {
83
+ exit: exitCodes.USAGE_ERROR
81
84
  });
82
85
  }
86
+ const confirmed = flags.yes || await this.promptForWildcardConfirmation(origin);
87
+ if (!confirmed) {
88
+ this.log('CORS origin not added');
89
+ this.exit(exitCodes.USER_ABORT);
90
+ }
83
91
  }
84
- const allowCredentials = flags.credentials === undefined ? await this.promptForCredentials(hasWildcard) : Boolean(flags.credentials);
92
+ const allowCredentials = flags.credentials === undefined ? this.isUnattended() ? false : await this.promptForCredentials(hasWildcard) : Boolean(flags.credentials);
85
93
  if (filteredOrigin !== origin) {
86
94
  this.log(`Normalized origin to: ${filteredOrigin}`);
87
95
  }
@@ -92,7 +100,7 @@ export class Add extends SanityCommand {
92
100
  projectId
93
101
  });
94
102
  addCorsDebug(`CORS origin added successfully`, response);
95
- this.log('CORS origin added successfully');
103
+ this.log('CORS origin added');
96
104
  } catch (error) {
97
105
  const err = error;
98
106
  addCorsDebug(`Error adding CORS origin`, err);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/cors/add.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\nimport {oneline} from 'oneline'\n\nimport {filterAndValidateOrigin} from '../../actions/cors/filterAndValidateOrigin.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createCorsOrigin} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst addCorsDebug = subdebug('cors:add')\n\nexport class Add extends SanityCommand<typeof Add> {\n static override args = {\n origin: Args.string({\n description: 'Origin to allow (e.g., https://example.com)',\n required: true,\n }),\n }\n\n static override description = 'Add a CORS origin to the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively add a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials',\n description: 'Add a localhost origin without credentials',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --credentials',\n description: 'Add a production origin with credentials allowed',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123',\n description: 'Add a CORS origin for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to add CORS origin to',\n semantics: 'override',\n }),\n credentials: Flags.boolean({\n allowNo: true,\n default: undefined,\n description: 'Allow credentials (token/cookie) to be sent from this origin',\n required: false,\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(Add)\n const {origin} = args\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'create', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Check if the origin argument looks like a file path and warn\n try {\n const isFile = fs.existsSync(path.join(process.cwd(), args.origin))\n if (isFile) {\n this.warn(`Origin \"${args.origin}?\" Remember to quote values (sanity cors add \"*\")`)\n }\n } catch {\n // Ignore errors checking if it's a file\n }\n\n const filteredOrigin = await filterAndValidateOrigin(origin, this.output)\n const hasWildcard = origin.includes('*')\n\n if (hasWildcard) {\n const confirmed = await this.promptForWildcardConfirmation(origin)\n if (!confirmed) {\n this.error('Operation cancelled', {exit: 1})\n }\n }\n\n const allowCredentials =\n flags.credentials === undefined\n ? await this.promptForCredentials(hasWildcard)\n : Boolean(flags.credentials)\n\n if (filteredOrigin !== origin) {\n this.log(`Normalized origin to: ${filteredOrigin}`)\n }\n\n try {\n const response = await createCorsOrigin({\n allowCredentials,\n origin: filteredOrigin,\n projectId,\n })\n\n addCorsDebug(`CORS origin added successfully`, response)\n\n this.log('CORS origin added successfully')\n } catch (error) {\n const err = error as Error\n\n addCorsDebug(`Error adding CORS origin`, err)\n this.error(`CORS origin addition failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n /**\n * Prompt the user for credentials\n *\n * @param hasWildcard - Whether the origin contains a wildcard\n * @returns - Whether to allow credentials\n */\n private async promptForCredentials(hasWildcard: boolean) {\n this.log('')\n if (hasWildcard) {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n We ${styleText(['red', 'underline'], 'HIGHLY')} recommend NOT allowing credentials\n on origins containing wildcards. If you are logged in to a Sanity studio or an app built with\n the Sanity App SDK, people will be able to send requests ${styleText('underline', 'on your behalf')}\n to read and modify data, from any matching origin. Please tread carefully!\n `)\n } else {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n Should this origin be allowed to send requests using authentication tokens or\n session cookies? Be aware that any script on this origin will be able to send\n requests ${styleText('underline', 'on your behalf')} to read and modify data if you\n are logged in to a Sanity studio or app. If this origin hosts a studio or an app built with\n the Sanity App SDK, you will need this, otherwise you should probably answer \"No\" (n).\n `)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Allow credentials to be sent from this origin? Please read the warning above.\n `,\n })\n }\n\n /**\n * Prompt the user for wildcard confirmation\n *\n * @param origin - The origin to check for wildcards\n * @returns - Whether to allow the origin\n */\n private async promptForWildcardConfirmation(origin: string) {\n this.log('')\n this.log(styleText('yellow', `${logSymbols.warning} Warning: Examples of allowed origins:`))\n\n if (origin === '*') {\n this.log('- http://www.some-malicious.site')\n this.log('- https://not.what-you-were-expecting.com')\n this.log('- https://high-traffic-site.com')\n this.log('- http://192.168.1.1:8080')\n } else {\n this.log(`- ${origin.replace(/:\\*/, ':1234').replaceAll('*', 'foo')}`)\n this.log(`- ${origin.replace(/:\\*/, ':3030').replaceAll('*', 'foo.bar')}`)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Using wildcards can be ${styleText('red', 'risky')}.\n Are you ${styleText('underline', 'absolutely sure')} you want to allow this origin?`,\n })\n }\n}\n"],"names":["fs","path","styleText","Args","Flags","SanityCommand","subdebug","confirm","logSymbols","oneline","filterAndValidateOrigin","promptForProject","createCorsOrigin","getProjectIdFlag","addCorsDebug","Add","args","origin","string","description","required","examples","command","flags","semantics","credentials","boolean","allowNo","default","undefined","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","isFile","existsSync","join","process","cwd","warn","filteredOrigin","output","hasWildcard","includes","confirmed","promptForWildcardConfirmation","error","exit","allowCredentials","promptForCredentials","Boolean","log","response","err","message","warning","replace","replaceAll"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/cors/add.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\nimport {oneline} from 'oneline'\n\nimport {filterAndValidateOrigin} from '../../actions/cors/filterAndValidateOrigin.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createCorsOrigin} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst addCorsDebug = subdebug('cors:add')\n\nexport class Add extends SanityCommand<typeof Add> {\n static override args = {\n origin: Args.string({\n description: 'Origin to allow (e.g., https://example.com)',\n required: true,\n }),\n }\n\n static override description = 'Add a CORS origin to the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively add a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials',\n description: 'Add a localhost origin without credentials',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --credentials',\n description: 'Add a production origin with credentials allowed',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123',\n description: 'Add a CORS origin for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to add CORS origin to',\n semantics: 'override',\n }),\n credentials: Flags.boolean({\n allowNo: true,\n default: undefined,\n description: 'Allow credentials (token/cookie) to be sent from this origin',\n required: false,\n }),\n yes: Flags.boolean({\n char: 'y',\n description: 'Confirm risky wildcard origins without prompting',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(Add)\n const {origin} = args\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'create', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Check if the origin argument looks like a file path and warn\n try {\n const isFile = fs.existsSync(path.join(process.cwd(), args.origin))\n if (isFile) {\n this.warn(`Origin \"${args.origin}?\" Remember to quote values (sanity cors add \"*\")`)\n }\n } catch {\n // Ignore errors checking if it's a file\n }\n\n const filteredOrigin = await filterAndValidateOrigin(origin, this.output)\n const hasWildcard = origin.includes('*')\n\n if (hasWildcard) {\n if (this.isUnattended() && !flags.yes) {\n this.error('Wildcard origins require confirmation. Pass `--yes` to continue.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n const confirmed = flags.yes || (await this.promptForWildcardConfirmation(origin))\n if (!confirmed) {\n this.log('CORS origin not added')\n this.exit(exitCodes.USER_ABORT)\n }\n }\n\n const allowCredentials =\n flags.credentials === undefined\n ? this.isUnattended()\n ? false\n : await this.promptForCredentials(hasWildcard)\n : Boolean(flags.credentials)\n\n if (filteredOrigin !== origin) {\n this.log(`Normalized origin to: ${filteredOrigin}`)\n }\n\n try {\n const response = await createCorsOrigin({\n allowCredentials,\n origin: filteredOrigin,\n projectId,\n })\n\n addCorsDebug(`CORS origin added successfully`, response)\n\n this.log('CORS origin added')\n } catch (error) {\n const err = error as Error\n\n addCorsDebug(`Error adding CORS origin`, err)\n this.error(`CORS origin addition failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n /**\n * Prompt the user for credentials\n *\n * @param hasWildcard - Whether the origin contains a wildcard\n * @returns - Whether to allow credentials\n */\n private async promptForCredentials(hasWildcard: boolean) {\n this.log('')\n if (hasWildcard) {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n We ${styleText(['red', 'underline'], 'HIGHLY')} recommend NOT allowing credentials\n on origins containing wildcards. If you are logged in to a Sanity studio or an app built with\n the Sanity App SDK, people will be able to send requests ${styleText('underline', 'on your behalf')}\n to read and modify data, from any matching origin. Please tread carefully!\n `)\n } else {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n Should this origin be allowed to send requests using authentication tokens or\n session cookies? Be aware that any script on this origin will be able to send\n requests ${styleText('underline', 'on your behalf')} to read and modify data if you\n are logged in to a Sanity studio or app. If this origin hosts a studio or an app built with\n the Sanity App SDK, you will need this, otherwise you should probably answer \"No\" (n).\n `)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Allow credentials to be sent from this origin? Please read the warning above.\n `,\n })\n }\n\n /**\n * Prompt the user for wildcard confirmation\n *\n * @param origin - The origin to check for wildcards\n * @returns - Whether to allow the origin\n */\n private async promptForWildcardConfirmation(origin: string) {\n this.log('')\n this.log(styleText('yellow', `${logSymbols.warning} Warning: Examples of allowed origins:`))\n\n if (origin === '*') {\n this.log('- http://www.some-malicious.site')\n this.log('- https://not.what-you-were-expecting.com')\n this.log('- https://high-traffic-site.com')\n this.log('- http://192.168.1.1:8080')\n } else {\n this.log(`- ${origin.replace(/:\\*/, ':1234').replaceAll('*', 'foo')}`)\n this.log(`- ${origin.replace(/:\\*/, ':3030').replaceAll('*', 'foo.bar')}`)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Using wildcards can be ${styleText('red', 'risky')}.\n Are you ${styleText('underline', 'absolutely sure')} you want to allow this origin?`,\n })\n }\n}\n"],"names":["fs","path","styleText","Args","Flags","exitCodes","SanityCommand","subdebug","confirm","logSymbols","oneline","filterAndValidateOrigin","promptForProject","createCorsOrigin","getProjectIdFlag","addCorsDebug","Add","args","origin","string","description","required","examples","command","flags","semantics","credentials","boolean","allowNo","default","undefined","yes","char","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","isFile","existsSync","join","process","cwd","warn","filteredOrigin","output","hasWildcard","includes","isUnattended","error","exit","USAGE_ERROR","confirmed","promptForWildcardConfirmation","log","USER_ABORT","allowCredentials","promptForCredentials","Boolean","response","err","message","warning","replace","replaceAll"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Args } from '@oclif/core';
2
- import { SanityCommand, subdebug } from '@sanity/cli-core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
3
  import { select } from '@sanity/cli-core/ux';
4
4
  import { promptForProject } from '../../prompts/promptForProject.js';
5
5
  import { deleteCorsOrigin, listCorsOrigins } from '../../services/cors.js';
@@ -35,6 +35,11 @@ export class Delete extends SanityCommand {
35
35
  };
36
36
  async run() {
37
37
  const { args } = await this.parse(Delete);
38
+ if (!args.origin && this.isUnattended()) {
39
+ this.error('Origin is required. Pass it as the `<origin>` argument.', {
40
+ exit: exitCodes.USAGE_ERROR
41
+ });
42
+ }
38
43
  // Ensure we have project context
39
44
  const projectId = await this.getProjectId({
40
45
  fallback: ()=>promptForProject({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/cors/delete.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, deleteCorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deleteCorsDebug = subdebug('cors:delete')\n\nexport class Delete extends SanityCommand<typeof Delete> {\n static override args = {\n origin: Args.string({\n description: 'Origin to delete (will prompt if not provided)',\n required: false,\n }),\n }\n\n static override description = 'Delete a CORS origin from the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively select and delete a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://example.com',\n description: 'Delete a specific CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'Delete a CORS origin from a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete CORS origin from',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n const {args} = await this.parse(Delete)\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'delete', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Get the origin ID to delete\n const originId = await this.promptForOrigin(args.origin, projectId)\n\n try {\n await deleteCorsOrigin({originId, projectId})\n\n this.log('Origin deleted')\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error deleting CORS origin ${originId} for project ${projectId}`, err)\n this.error(`Origin deletion failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n private async promptForOrigin(\n specifiedOrigin: string | undefined,\n projectId: string,\n ): Promise<number> {\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`Failed to fetch CORS origins:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.error('No CORS origins configured for this project.', {exit: 1})\n }\n\n // If origin is specified, find it in the list\n if (specifiedOrigin) {\n const specifiedOriginLower = specifiedOrigin.toLowerCase()\n const selectedOrigin = origins.find(\n (origin) => origin.origin.toLowerCase() === specifiedOriginLower,\n )\n\n if (!selectedOrigin) {\n this.error(`Origin \"${specifiedOrigin}\" not found`, {exit: 1})\n }\n\n return selectedOrigin.id\n }\n\n // If no origin specified, prompt user to select one\n const choices = origins.map((origin) => ({\n name: origin.origin,\n value: origin.id,\n }))\n\n const selectedId = await select({\n choices,\n message: 'Select origin to delete',\n })\n\n return selectedId\n }\n}\n"],"names":["Args","SanityCommand","subdebug","select","promptForProject","deleteCorsOrigin","listCorsOrigins","getProjectIdFlag","deleteCorsDebug","Delete","args","origin","string","description","required","examples","command","flags","semantics","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","originId","promptForOrigin","log","error","err","message","exit","specifiedOrigin","origins","length","specifiedOriginLower","toLowerCase","selectedOrigin","find","id","choices","map","name","value","selectedId"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,MAAM,QAAO,sBAAqB;AAE1C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAyBC,gBAAgB,EAAEC,eAAe,QAAO,yBAAwB;AACzF,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,kBAAkBN,SAAS;AAEjC,OAAO,MAAMO,eAAeR;IAC1B,OAAgBS,OAAO;QACrBC,QAAQX,KAAKY,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,wCAAuC;IAErE,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGV,iBAAiB;YAClBM,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAC;IAED,MAAaC,MAAqB;QAChC,MAAM,EAACT,IAAI,EAAC,GAAG,MAAM,IAAI,CAACU,KAAK,CAACX;QAEhC,iCAAiC;QACjC,MAAMY,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAUC,YAAY;wBAAqB;qBAAE;gBAC7E;QACJ;QAEA,8BAA8B;QAC9B,MAAMC,WAAW,MAAM,IAAI,CAACC,eAAe,CAAClB,KAAKC,MAAM,EAAEU;QAEzD,IAAI;YACF,MAAMhB,iBAAiB;gBAACsB;gBAAUN;YAAS;YAE3C,IAAI,CAACQ,GAAG,CAAC;QACX,EAAE,OAAOC,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,2BAA2B,EAAEmB,SAAS,aAAa,EAAEN,WAAW,EAAEU;YACnF,IAAI,CAACD,KAAK,CAAC,CAAC,yBAAyB,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QAChE;IACF;IAEA,MAAcL,gBACZM,eAAmC,EACnCb,SAAiB,EACA;QACjB,IAAIc;QACJ,IAAI;YACFA,UAAU,MAAM7B,gBAAgBe;QAClC,EAAE,OAAOS,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,wCAAwC,EAAEa,WAAW,EAAEU;YACxE,IAAI,CAACD,KAAK,CAAC,CAAC,+BAA+B,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QACtE;QAEA,IAAIE,QAAQC,MAAM,KAAK,GAAG;YACxB,IAAI,CAACN,KAAK,CAAC,gDAAgD;gBAACG,MAAM;YAAC;QACrE;QAEA,8CAA8C;QAC9C,IAAIC,iBAAiB;YACnB,MAAMG,uBAAuBH,gBAAgBI,WAAW;YACxD,MAAMC,iBAAiBJ,QAAQK,IAAI,CACjC,CAAC7B,SAAWA,OAAOA,MAAM,CAAC2B,WAAW,OAAOD;YAG9C,IAAI,CAACE,gBAAgB;gBACnB,IAAI,CAACT,KAAK,CAAC,CAAC,QAAQ,EAAEI,gBAAgB,WAAW,CAAC,EAAE;oBAACD,MAAM;gBAAC;YAC9D;YAEA,OAAOM,eAAeE,EAAE;QAC1B;QAEA,oDAAoD;QACpD,MAAMC,UAAUP,QAAQQ,GAAG,CAAC,CAAChC,SAAY,CAAA;gBACvCiC,MAAMjC,OAAOA,MAAM;gBACnBkC,OAAOlC,OAAO8B,EAAE;YAClB,CAAA;QAEA,MAAMK,aAAa,MAAM3C,OAAO;YAC9BuC;YACAV,SAAS;QACX;QAEA,OAAOc;IACT;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/cors/delete.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, deleteCorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deleteCorsDebug = subdebug('cors:delete')\n\nexport class Delete extends SanityCommand<typeof Delete> {\n static override args = {\n origin: Args.string({\n description: 'Origin to delete (will prompt if not provided)',\n required: false,\n }),\n }\n\n static override description = 'Delete a CORS origin from the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively select and delete a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://example.com',\n description: 'Delete a specific CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'Delete a CORS origin from a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete CORS origin from',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n const {args} = await this.parse(Delete)\n\n if (!args.origin && this.isUnattended()) {\n this.error('Origin is required. Pass it as the `<origin>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'delete', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Get the origin ID to delete\n const originId = await this.promptForOrigin(args.origin, projectId)\n\n try {\n await deleteCorsOrigin({originId, projectId})\n\n this.log('Origin deleted')\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error deleting CORS origin ${originId} for project ${projectId}`, err)\n this.error(`Origin deletion failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n private async promptForOrigin(\n specifiedOrigin: string | undefined,\n projectId: string,\n ): Promise<number> {\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`Failed to fetch CORS origins:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.error('No CORS origins configured for this project.', {exit: 1})\n }\n\n // If origin is specified, find it in the list\n if (specifiedOrigin) {\n const specifiedOriginLower = specifiedOrigin.toLowerCase()\n const selectedOrigin = origins.find(\n (origin) => origin.origin.toLowerCase() === specifiedOriginLower,\n )\n\n if (!selectedOrigin) {\n this.error(`Origin \"${specifiedOrigin}\" not found`, {exit: 1})\n }\n\n return selectedOrigin.id\n }\n\n // If no origin specified, prompt user to select one\n const choices = origins.map((origin) => ({\n name: origin.origin,\n value: origin.id,\n }))\n\n const selectedId = await select({\n choices,\n message: 'Select origin to delete',\n })\n\n return selectedId\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","select","promptForProject","deleteCorsOrigin","listCorsOrigins","getProjectIdFlag","deleteCorsDebug","Delete","args","origin","string","description","required","examples","command","flags","semantics","run","parse","isUnattended","error","exit","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","originId","promptForOrigin","log","err","message","specifiedOrigin","origins","length","specifiedOriginLower","toLowerCase","selectedOrigin","find","id","choices","map","name","value","selectedId"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Args } from '@oclif/core';
2
- import { SanityCommand, subdebug } from '@sanity/cli-core';
2
+ import { CLIError } from '@oclif/core/errors';
3
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
4
  import { validateDatasetAliasName } from '../../../actions/dataset/validateDatasetAliasName.js';
4
5
  import { validateDatasetName } from '../../../actions/dataset/validateDatasetName.js';
5
6
  import { promptForDatasetAliasName } from '../../../prompts/promptForDatasetAliasName.js';
@@ -51,6 +52,27 @@ export class CreateAliasCommand extends SanityCommand {
51
52
  ];
52
53
  async run() {
53
54
  const { args } = await this.parse(CreateAliasCommand);
55
+ if (!args.aliasName && this.isUnattended()) {
56
+ this.error('Dataset alias name is required. Pass it as the `<aliasName>` argument.', {
57
+ exit: exitCodes.USAGE_ERROR
58
+ });
59
+ }
60
+ if (args.aliasName) {
61
+ const nameError = validateDatasetAliasName(args.aliasName);
62
+ if (nameError) {
63
+ this.error(nameError, {
64
+ exit: exitCodes.USAGE_ERROR
65
+ });
66
+ }
67
+ }
68
+ if (args.targetDataset) {
69
+ const datasetErr = validateDatasetName(args.targetDataset);
70
+ if (datasetErr) {
71
+ this.error(datasetErr, {
72
+ exit: exitCodes.USAGE_ERROR
73
+ });
74
+ }
75
+ }
54
76
  const projectId = await this.getProjectId({
55
77
  fallback: ()=>promptForProject({
56
78
  requiredPermissions: [
@@ -80,22 +102,6 @@ export class CreateAliasCommand extends SanityCommand {
80
102
  exit: 1
81
103
  });
82
104
  }
83
- if (args.aliasName) {
84
- const nameError = validateDatasetAliasName(args.aliasName);
85
- if (nameError) {
86
- this.error(nameError, {
87
- exit: 1
88
- });
89
- }
90
- }
91
- if (args.targetDataset) {
92
- const datasetErr = validateDatasetName(args.targetDataset);
93
- if (datasetErr) {
94
- this.error(datasetErr, {
95
- exit: 1
96
- });
97
- }
98
- }
99
105
  try {
100
106
  const [datasetsResponse, aliases] = await Promise.all([
101
107
  listDatasets(projectId),
@@ -115,7 +121,7 @@ export class CreateAliasCommand extends SanityCommand {
115
121
  exit: 1
116
122
  });
117
123
  }
118
- const targetDataset = args.targetDataset || (datasets.length > 0 ? await selectDataset(datasets) : null);
124
+ const targetDataset = args.targetDataset || (!this.isUnattended() && datasets.length > 0 ? await selectDataset(datasets) : null);
119
125
  if (targetDataset && !datasets.includes(targetDataset)) {
120
126
  this.error(`Dataset "${targetDataset}" does not exist. Available datasets: ${datasets.join(', ')}`, {
121
127
  exit: 1
@@ -125,6 +131,7 @@ export class CreateAliasCommand extends SanityCommand {
125
131
  const linkMessage = targetDataset ? ` and linked to ${targetDataset}` : '';
126
132
  this.log(`Dataset alias ${aliasOutputName} created${linkMessage} successfully`);
127
133
  } catch (error) {
134
+ if (error instanceof CLIError) throw error;
128
135
  createAliasDebug(`Error creating dataset alias`, error);
129
136
  this.error(`Dataset alias creation failed: ${error instanceof Error ? error.message : String(error)}`, {
130
137
  exit: 1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/commands/datasets/alias/create.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {validateDatasetName} from '../../../actions/dataset/validateDatasetName.js'\nimport {promptForDatasetAliasName} from '../../../prompts/promptForDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {selectDataset} from '../../../prompts/selectDataset.js'\nimport {ALIAS_PREFIX, createAlias, listAliases} from '../../../services/datasetAliases.js'\nimport {listDatasets} from '../../../services/datasets.js'\nimport {getProjectFeatures} from '../../../services/getProjectFeatures.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst createAliasDebug = subdebug('dataset:alias:create')\n\nexport class CreateAliasCommand extends SanityCommand<typeof CreateAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to create',\n required: false,\n }),\n targetDataset: Args.string({\n description: 'Target dataset name to link the alias to',\n required: false,\n }),\n }\n\n static override description = 'Create a dataset alias for the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123 conference conf-2025',\n description: 'Create alias in a specific project',\n },\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create an alias with interactive prompts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Create alias named \"conference\" with interactive dataset selection',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025',\n description: 'Create alias \"conference\" linked to \"conf-2025\" dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to create dataset alias in',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:create']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(CreateAliasCommand)\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let canCreateAlias = false\n try {\n const features = await getProjectFeatures(projectId)\n canCreateAlias = features.includes('advancedDatasetManagement')\n } catch (error) {\n createAliasDebug(`Error getting project features`, error)\n this.error('Failed to get project features', {exit: 1})\n }\n if (!canCreateAlias) {\n this.error('This project cannot create a dataset alias - see https://www.sanity.io/pricing', {\n exit: 1,\n })\n }\n\n if (args.aliasName) {\n const nameError = validateDatasetAliasName(args.aliasName)\n if (nameError) {\n this.error(nameError, {exit: 1})\n }\n }\n\n if (args.targetDataset) {\n const datasetErr = validateDatasetName(args.targetDataset)\n if (datasetErr) {\n this.error(datasetErr, {exit: 1})\n }\n }\n\n try {\n const [datasetsResponse, aliases] = await Promise.all([\n listDatasets(projectId),\n listAliases(projectId),\n ])\n\n const datasets = datasetsResponse.map((ds: {name: string}) => ds.name)\n const existingAliases = aliases.map((alias: {name: string}) => alias.name)\n\n let aliasName = args.aliasName || (await promptForDatasetAliasName())\n let aliasOutputName = aliasName\n\n if (aliasName.startsWith(ALIAS_PREFIX)) {\n aliasName = aliasName.slice(1)\n } else {\n aliasOutputName = `${ALIAS_PREFIX}${aliasName}`\n }\n\n if (existingAliases.includes(aliasName)) {\n this.error(`Dataset alias \"${aliasOutputName}\" already exists`, {exit: 1})\n }\n\n const targetDataset =\n args.targetDataset || (datasets.length > 0 ? await selectDataset(datasets) : null)\n\n if (targetDataset && !datasets.includes(targetDataset)) {\n this.error(\n `Dataset \"${targetDataset}\" does not exist. Available datasets: ${datasets.join(', ')}`,\n {exit: 1},\n )\n }\n\n await createAlias(projectId, aliasName, targetDataset)\n\n const linkMessage = targetDataset ? ` and linked to ${targetDataset}` : ''\n this.log(`Dataset alias ${aliasOutputName} created${linkMessage} successfully`)\n } catch (error) {\n createAliasDebug(`Error creating dataset alias`, error)\n this.error(\n `Dataset alias creation failed: ${error instanceof Error ? error.message : String(error)}`,\n {exit: 1},\n )\n }\n }\n}\n"],"names":["Args","SanityCommand","subdebug","validateDatasetAliasName","validateDatasetName","promptForDatasetAliasName","promptForProject","selectDataset","ALIAS_PREFIX","createAlias","listAliases","listDatasets","getProjectFeatures","getProjectIdFlag","createAliasDebug","CreateAliasCommand","args","aliasName","string","description","required","targetDataset","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","canCreateAlias","features","includes","error","exit","nameError","datasetErr","datasetsResponse","aliases","Promise","all","datasets","map","ds","name","existingAliases","alias","aliasOutputName","startsWith","slice","length","join","linkMessage","log","Error","message","String"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/commands/datasets/alias/create.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {validateDatasetName} from '../../../actions/dataset/validateDatasetName.js'\nimport {promptForDatasetAliasName} from '../../../prompts/promptForDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {selectDataset} from '../../../prompts/selectDataset.js'\nimport {ALIAS_PREFIX, createAlias, listAliases} from '../../../services/datasetAliases.js'\nimport {listDatasets} from '../../../services/datasets.js'\nimport {getProjectFeatures} from '../../../services/getProjectFeatures.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst createAliasDebug = subdebug('dataset:alias:create')\n\nexport class CreateAliasCommand extends SanityCommand<typeof CreateAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to create',\n required: false,\n }),\n targetDataset: Args.string({\n description: 'Target dataset name to link the alias to',\n required: false,\n }),\n }\n\n static override description = 'Create a dataset alias for the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123 conference conf-2025',\n description: 'Create alias in a specific project',\n },\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create an alias with interactive prompts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Create alias named \"conference\" with interactive dataset selection',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025',\n description: 'Create alias \"conference\" linked to \"conf-2025\" dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to create dataset alias in',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:create']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(CreateAliasCommand)\n\n if (!args.aliasName && this.isUnattended()) {\n this.error('Dataset alias name is required. Pass it as the `<aliasName>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (args.aliasName) {\n const nameError = validateDatasetAliasName(args.aliasName)\n if (nameError) {\n this.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n if (args.targetDataset) {\n const datasetErr = validateDatasetName(args.targetDataset)\n if (datasetErr) {\n this.error(datasetErr, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let canCreateAlias = false\n try {\n const features = await getProjectFeatures(projectId)\n canCreateAlias = features.includes('advancedDatasetManagement')\n } catch (error) {\n createAliasDebug(`Error getting project features`, error)\n this.error('Failed to get project features', {exit: 1})\n }\n if (!canCreateAlias) {\n this.error('This project cannot create a dataset alias - see https://www.sanity.io/pricing', {\n exit: 1,\n })\n }\n\n try {\n const [datasetsResponse, aliases] = await Promise.all([\n listDatasets(projectId),\n listAliases(projectId),\n ])\n\n const datasets = datasetsResponse.map((ds: {name: string}) => ds.name)\n const existingAliases = aliases.map((alias: {name: string}) => alias.name)\n\n let aliasName = args.aliasName || (await promptForDatasetAliasName())\n let aliasOutputName = aliasName\n\n if (aliasName.startsWith(ALIAS_PREFIX)) {\n aliasName = aliasName.slice(1)\n } else {\n aliasOutputName = `${ALIAS_PREFIX}${aliasName}`\n }\n\n if (existingAliases.includes(aliasName)) {\n this.error(`Dataset alias \"${aliasOutputName}\" already exists`, {exit: 1})\n }\n\n const targetDataset =\n args.targetDataset ||\n (!this.isUnattended() && datasets.length > 0 ? await selectDataset(datasets) : null)\n\n if (targetDataset && !datasets.includes(targetDataset)) {\n this.error(\n `Dataset \"${targetDataset}\" does not exist. Available datasets: ${datasets.join(', ')}`,\n {exit: 1},\n )\n }\n\n await createAlias(projectId, aliasName, targetDataset)\n\n const linkMessage = targetDataset ? ` and linked to ${targetDataset}` : ''\n this.log(`Dataset alias ${aliasOutputName} created${linkMessage} successfully`)\n } catch (error) {\n if (error instanceof CLIError) throw error\n createAliasDebug(`Error creating dataset alias`, error)\n this.error(\n `Dataset alias creation failed: ${error instanceof Error ? error.message : String(error)}`,\n {exit: 1},\n )\n }\n }\n}\n"],"names":["Args","CLIError","exitCodes","SanityCommand","subdebug","validateDatasetAliasName","validateDatasetName","promptForDatasetAliasName","promptForProject","selectDataset","ALIAS_PREFIX","createAlias","listAliases","listDatasets","getProjectFeatures","getProjectIdFlag","createAliasDebug","CreateAliasCommand","args","aliasName","string","description","required","targetDataset","examples","command","flags","semantics","hiddenAliases","run","parse","isUnattended","error","exit","USAGE_ERROR","nameError","datasetErr","projectId","getProjectId","fallback","requiredPermissions","grant","permission","canCreateAlias","features","includes","datasetsResponse","aliases","Promise","all","datasets","map","ds","name","existingAliases","alias","aliasOutputName","startsWith","slice","length","join","linkMessage","log","Error","message","String"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import { SanityCommand, subdebug } from '@sanity/cli-core';
2
+ import { CLIError } from '@oclif/core/errors';
3
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
4
  import { input } from '@sanity/cli-core/ux';
4
5
  import { processAliasName } from '../../../actions/dataset/processAliasName.js';
5
6
  import { validateDatasetAliasName } from '../../../actions/dataset/validateDatasetAliasName.js';
@@ -41,6 +42,13 @@ export class DeleteAliasCommand extends SanityCommand {
41
42
  async run() {
42
43
  const { args, flags } = await this.parse(DeleteAliasCommand);
43
44
  const { force } = flags;
45
+ const { apiName, displayName } = processAliasName(args.aliasName);
46
+ const nameError = validateDatasetAliasName(apiName);
47
+ if (nameError) {
48
+ this.error(nameError, {
49
+ exit: exitCodes.USAGE_ERROR
50
+ });
51
+ }
44
52
  const projectId = await this.getProjectId({
45
53
  fallback: ()=>promptForProject({
46
54
  requiredPermissions: [
@@ -55,13 +63,6 @@ export class DeleteAliasCommand extends SanityCommand {
55
63
  ]
56
64
  })
57
65
  });
58
- const { apiName, displayName } = processAliasName(args.aliasName);
59
- const nameError = validateDatasetAliasName(apiName);
60
- if (nameError) {
61
- this.error(nameError, {
62
- exit: 1
63
- });
64
- }
65
66
  try {
66
67
  const aliases = await listAliases(projectId);
67
68
  const existingAlias = aliases.find((alias)=>alias.name === apiName);
@@ -73,11 +74,17 @@ export class DeleteAliasCommand extends SanityCommand {
73
74
  if (force) {
74
75
  this.warn(`'--force' used: skipping confirmation, deleting alias "${displayName}"`);
75
76
  } else {
77
+ if (this.isUnattended()) {
78
+ this.error('Dataset alias deletion requires confirmation. Re-run with `--force`.', {
79
+ exit: exitCodes.USAGE_ERROR
80
+ });
81
+ }
76
82
  await this.confirmDeletion(apiName, existingAlias.datasetName);
77
83
  }
78
84
  await removeAlias(projectId, apiName);
79
85
  this.log('Dataset alias deleted successfully');
80
86
  } catch (error) {
87
+ if (error instanceof CLIError) throw error;
81
88
  const errorMessage = error instanceof Error ? error.message : String(error);
82
89
  deleteAliasDebug(`Error deleting dataset alias ${args.aliasName}`, error);
83
90
  this.error(`Dataset alias deletion failed: ${errorMessage}`, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/commands/datasets/alias/delete.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input} from '@sanity/cli-core/ux'\n\nimport {processAliasName} from '../../../actions/dataset/processAliasName.js'\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {listAliases, removeAlias} from '../../../services/datasetAliases.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst deleteAliasDebug = subdebug('dataset:alias:delete')\n\nexport class DeleteAliasCommand extends SanityCommand<typeof DeleteAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to delete',\n required: true,\n }),\n }\n\n static override description = 'Delete a dataset alias from the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Delete alias named \"conference\" with confirmation prompt',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference --force',\n description: 'Delete alias named \"conference\" without confirmation prompt',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete dataset alias from',\n semantics: 'override',\n }),\n force: Flags.boolean({\n description: 'Skip confirmation prompt and delete immediately',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:delete']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(DeleteAliasCommand)\n const {force} = flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'delete', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n const {apiName, displayName} = processAliasName(args.aliasName)\n\n const nameError = validateDatasetAliasName(apiName)\n if (nameError) {\n this.error(nameError, {exit: 1})\n }\n\n try {\n const aliases = await listAliases(projectId)\n const existingAlias = aliases.find((alias) => alias.name === apiName)\n\n if (!existingAlias) {\n this.error(`Dataset alias \"${displayName}\" does not exist`, {\n exit: 1,\n })\n }\n\n if (force) {\n this.warn(`'--force' used: skipping confirmation, deleting alias \"${displayName}\"`)\n } else {\n await this.confirmDeletion(apiName, existingAlias.datasetName)\n }\n\n await removeAlias(projectId, apiName)\n\n this.log('Dataset alias deleted successfully')\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n deleteAliasDebug(`Error deleting dataset alias ${args.aliasName}`, error)\n this.error(`Dataset alias deletion failed: ${errorMessage}`, {exit: 1})\n }\n }\n\n private async confirmDeletion(aliasName: string, linkedDataset?: string | null): Promise<void> {\n const message = linkedDataset\n ? `This dataset alias is linked to ${linkedDataset}. Are you ABSOLUTELY sure you want to delete this dataset alias?\\n Type the name of the dataset alias to confirm delete:`\n : `Are you ABSOLUTELY sure you want to delete this dataset alias?\\n Type the name of the dataset alias to confirm delete:`\n\n await input({\n message,\n validate: (input) => {\n const trimmed = input.trim().replace(/^~/, '')\n return trimmed === aliasName || 'Incorrect dataset alias name. Ctrl + C to cancel delete.'\n },\n })\n }\n}\n"],"names":["Args","Flags","SanityCommand","subdebug","input","processAliasName","validateDatasetAliasName","promptForProject","listAliases","removeAlias","getProjectIdFlag","deleteAliasDebug","DeleteAliasCommand","args","aliasName","string","description","required","examples","command","flags","semantics","force","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","apiName","displayName","nameError","error","exit","aliases","existingAlias","find","alias","name","warn","confirmDeletion","datasetName","log","errorMessage","Error","message","String","linkedDataset","validate","trimmed","trim","replace"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/commands/datasets/alias/delete.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input} from '@sanity/cli-core/ux'\n\nimport {processAliasName} from '../../../actions/dataset/processAliasName.js'\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {listAliases, removeAlias} from '../../../services/datasetAliases.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst deleteAliasDebug = subdebug('dataset:alias:delete')\n\nexport class DeleteAliasCommand extends SanityCommand<typeof DeleteAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to delete',\n required: true,\n }),\n }\n\n static override description = 'Delete a dataset alias from the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Delete alias named \"conference\" with confirmation prompt',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference --force',\n description: 'Delete alias named \"conference\" without confirmation prompt',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete dataset alias from',\n semantics: 'override',\n }),\n force: Flags.boolean({\n description: 'Skip confirmation prompt and delete immediately',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:delete']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(DeleteAliasCommand)\n const {force} = flags\n\n const {apiName, displayName} = processAliasName(args.aliasName)\n\n const nameError = validateDatasetAliasName(apiName)\n if (nameError) {\n this.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'delete', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n try {\n const aliases = await listAliases(projectId)\n const existingAlias = aliases.find((alias) => alias.name === apiName)\n\n if (!existingAlias) {\n this.error(`Dataset alias \"${displayName}\" does not exist`, {\n exit: 1,\n })\n }\n\n if (force) {\n this.warn(`'--force' used: skipping confirmation, deleting alias \"${displayName}\"`)\n } else {\n if (this.isUnattended()) {\n this.error('Dataset alias deletion requires confirmation. Re-run with `--force`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n await this.confirmDeletion(apiName, existingAlias.datasetName)\n }\n\n await removeAlias(projectId, apiName)\n\n this.log('Dataset alias deleted successfully')\n } catch (error) {\n if (error instanceof CLIError) throw error\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n deleteAliasDebug(`Error deleting dataset alias ${args.aliasName}`, error)\n this.error(`Dataset alias deletion failed: ${errorMessage}`, {exit: 1})\n }\n }\n\n private async confirmDeletion(aliasName: string, linkedDataset?: string | null): Promise<void> {\n const message = linkedDataset\n ? `This dataset alias is linked to ${linkedDataset}. Are you ABSOLUTELY sure you want to delete this dataset alias?\\n Type the name of the dataset alias to confirm delete:`\n : `Are you ABSOLUTELY sure you want to delete this dataset alias?\\n Type the name of the dataset alias to confirm delete:`\n\n await input({\n message,\n validate: (input) => {\n const trimmed = input.trim().replace(/^~/, '')\n return trimmed === aliasName || 'Incorrect dataset alias name. Ctrl + C to cancel delete.'\n },\n })\n }\n}\n"],"names":["Args","Flags","CLIError","exitCodes","SanityCommand","subdebug","input","processAliasName","validateDatasetAliasName","promptForProject","listAliases","removeAlias","getProjectIdFlag","deleteAliasDebug","DeleteAliasCommand","args","aliasName","string","description","required","examples","command","flags","semantics","force","boolean","hiddenAliases","run","parse","apiName","displayName","nameError","error","exit","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","aliases","existingAlias","find","alias","name","warn","isUnattended","confirmDeletion","datasetName","log","errorMessage","Error","message","String","linkedDataset","validate","trimmed","trim","replace"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import { SanityCommand, subdebug } from '@sanity/cli-core';
2
+ import { CLIError } from '@oclif/core/errors';
3
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
4
  import { input } from '@sanity/cli-core/ux';
4
5
  import { processAliasName } from '../../../actions/dataset/processAliasName.js';
5
6
  import { validateDatasetAliasName } from '../../../actions/dataset/validateDatasetAliasName.js';
@@ -9,6 +10,7 @@ import { promptForProject } from '../../../prompts/promptForProject.js';
9
10
  import { selectDataset } from '../../../prompts/selectDataset.js';
10
11
  import { listAliases, updateAlias } from '../../../services/datasetAliases.js';
11
12
  import { listDatasets } from '../../../services/datasets.js';
13
+ import { formatCliErrorMessages } from '../../../util/formatCliErrorMessages.js';
12
14
  import { getProjectIdFlag } from '../../../util/sharedFlags.js';
13
15
  const linkAliasDebug = subdebug('dataset:alias:link');
14
16
  export class LinkAliasCommand extends SanityCommand {
@@ -57,26 +59,26 @@ export class LinkAliasCommand extends SanityCommand {
57
59
  async run() {
58
60
  const { args, flags } = await this.parse(LinkAliasCommand);
59
61
  const { force } = flags;
60
- const projectId = await this.getProjectId({
61
- fallback: ()=>promptForProject({
62
- requiredPermissions: [
63
- {
64
- grant: 'read',
65
- permission: 'sanity.project.datasets'
66
- },
67
- {
68
- grant: 'update',
69
- permission: 'sanity.project.datasets'
70
- }
71
- ]
72
- })
73
- });
62
+ if (this.isUnattended()) {
63
+ const errors = [];
64
+ if (!args.aliasName) {
65
+ errors.push('Dataset alias name is required. Pass it as the `<aliasName>` argument.');
66
+ }
67
+ if (!args.targetDataset) {
68
+ errors.push('Target dataset is required. Pass it as the `<targetDataset>` argument.');
69
+ }
70
+ if (errors.length > 0) {
71
+ this.error(formatCliErrorMessages(errors), {
72
+ exit: exitCodes.USAGE_ERROR
73
+ });
74
+ }
75
+ }
74
76
  if (args.aliasName) {
75
77
  const { apiName } = processAliasName(args.aliasName);
76
78
  const nameError = validateDatasetAliasName(apiName);
77
79
  if (nameError) {
78
80
  this.error(nameError, {
79
- exit: 1
81
+ exit: exitCodes.USAGE_ERROR
80
82
  });
81
83
  }
82
84
  }
@@ -84,10 +86,24 @@ export class LinkAliasCommand extends SanityCommand {
84
86
  const datasetErr = validateDatasetName(args.targetDataset);
85
87
  if (datasetErr) {
86
88
  this.error(datasetErr, {
87
- exit: 1
89
+ exit: exitCodes.USAGE_ERROR
88
90
  });
89
91
  }
90
92
  }
93
+ const projectId = await this.getProjectId({
94
+ fallback: ()=>promptForProject({
95
+ requiredPermissions: [
96
+ {
97
+ grant: 'read',
98
+ permission: 'sanity.project.datasets'
99
+ },
100
+ {
101
+ grant: 'update',
102
+ permission: 'sanity.project.datasets'
103
+ }
104
+ ]
105
+ })
106
+ });
91
107
  try {
92
108
  const [datasetsResponse, aliases] = await Promise.all([
93
109
  listDatasets(projectId),
@@ -122,6 +138,11 @@ export class LinkAliasCommand extends SanityCommand {
122
138
  });
123
139
  }
124
140
  if (existingAlias.datasetName && !force) {
141
+ if (this.isUnattended()) {
142
+ this.error('Relinking a dataset alias requires confirmation. Re-run with `--force`.', {
143
+ exit: exitCodes.USAGE_ERROR
144
+ });
145
+ }
125
146
  await this.confirmRelink(existingAlias.datasetName, targetDataset);
126
147
  } else if (force && existingAlias.datasetName) {
127
148
  this.warn(`'--force' used: skipping confirmation, linking alias to ${targetDataset}`);
@@ -129,6 +150,7 @@ export class LinkAliasCommand extends SanityCommand {
129
150
  await updateAlias(projectId, apiName, targetDataset);
130
151
  this.log(`Dataset alias ${displayName} linked to ${targetDataset} successfully`);
131
152
  } catch (error) {
153
+ if (error instanceof CLIError) throw error;
132
154
  linkAliasDebug(`Error linking dataset alias`, error);
133
155
  this.error(`Dataset alias linking failed: ${error instanceof Error ? error.message : String(error)}`, {
134
156
  exit: 1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/commands/datasets/alias/link.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input} from '@sanity/cli-core/ux'\n\nimport {processAliasName} from '../../../actions/dataset/processAliasName.js'\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {validateDatasetName} from '../../../actions/dataset/validateDatasetName.js'\nimport {promptForDatasetAliasName} from '../../../prompts/promptForDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {selectDataset} from '../../../prompts/selectDataset.js'\nimport {listAliases, updateAlias} from '../../../services/datasetAliases.js'\nimport {listDatasets} from '../../../services/datasets.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst linkAliasDebug = subdebug('dataset:alias:link')\n\nexport class LinkAliasCommand extends SanityCommand<typeof LinkAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to link',\n required: false,\n }),\n targetDataset: Args.string({\n description: 'Target dataset name to link the alias to',\n required: false,\n }),\n }\n\n static override description = 'Link a dataset alias to a dataset in the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Link an alias with interactive prompts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Link alias named \"conference\" with interactive dataset selection',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025',\n description: 'Link alias \"conference\" to \"conf-2025\" dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025 --force',\n description: 'Force link without confirmation (skip relink prompt)',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to link dataset alias in',\n semantics: 'override',\n }),\n force: Flags.boolean({\n description: 'Skip confirmation prompt when relinking existing alias',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:link']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(LinkAliasCommand)\n const {force} = flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n if (args.aliasName) {\n const {apiName} = processAliasName(args.aliasName)\n const nameError = validateDatasetAliasName(apiName)\n if (nameError) {\n this.error(nameError, {exit: 1})\n }\n }\n\n if (args.targetDataset) {\n const datasetErr = validateDatasetName(args.targetDataset)\n if (datasetErr) {\n this.error(datasetErr, {exit: 1})\n }\n }\n\n try {\n const [datasetsResponse, aliases] = await Promise.all([\n listDatasets(projectId),\n listAliases(projectId),\n ])\n\n const datasets = datasetsResponse.map((ds) => ds.name)\n\n const aliasNameInput = args.aliasName || (await promptForDatasetAliasName())\n\n const {apiName, displayName} = processAliasName(aliasNameInput)\n\n const existingAlias = aliases.find((alias) => alias.name === apiName)\n if (!existingAlias) {\n const availableAliases = aliases.map((a) => `~${a.name}`).join(', ')\n this.error(\n `Dataset alias \"${displayName}\" does not exist. Available aliases: ${availableAliases}`,\n {exit: 1},\n )\n }\n\n const targetDataset =\n args.targetDataset ||\n (datasets.length > 0\n ? await selectDataset(datasets, {\n message: 'Select target dataset to link alias to:',\n })\n : null)\n\n if (!targetDataset) {\n this.error('No datasets available to link to', {exit: 1})\n }\n\n if (!datasets.includes(targetDataset)) {\n this.error(\n `Dataset \"${targetDataset}\" does not exist. Available datasets: ${datasets.join(', ')}`,\n {exit: 1},\n )\n }\n\n if (existingAlias.datasetName === targetDataset) {\n this.error(`Dataset alias ${displayName} already linked to ${targetDataset}`, {exit: 1})\n }\n\n if (existingAlias.datasetName && !force) {\n await this.confirmRelink(existingAlias.datasetName, targetDataset)\n } else if (force && existingAlias.datasetName) {\n this.warn(`'--force' used: skipping confirmation, linking alias to ${targetDataset}`)\n }\n\n await updateAlias(projectId, apiName, targetDataset)\n\n this.log(`Dataset alias ${displayName} linked to ${targetDataset} successfully`)\n } catch (error) {\n linkAliasDebug(`Error linking dataset alias`, error)\n this.error(\n `Dataset alias linking failed: ${error instanceof Error ? error.message : String(error)}`,\n {exit: 1},\n )\n }\n }\n\n private async confirmRelink(currentDataset: string, newDataset: string): Promise<void> {\n await input({\n message: `This alias is linked to dataset <${currentDataset}>. Are you ABSOLUTELY sure you want to link this dataset alias to ${newDataset}?\\n Type YES/NO:`,\n validate: (input) => {\n const response = input.toLowerCase().trim()\n return response === 'yes' || 'Type YES to confirm or Ctrl + C to cancel dataset alias link.'\n },\n })\n }\n}\n"],"names":["Args","Flags","SanityCommand","subdebug","input","processAliasName","validateDatasetAliasName","validateDatasetName","promptForDatasetAliasName","promptForProject","selectDataset","listAliases","updateAlias","listDatasets","getProjectIdFlag","linkAliasDebug","LinkAliasCommand","args","aliasName","string","description","required","targetDataset","examples","command","flags","semantics","force","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","apiName","nameError","error","exit","datasetErr","datasetsResponse","aliases","Promise","all","datasets","map","ds","name","aliasNameInput","displayName","existingAlias","find","alias","availableAliases","a","join","length","message","includes","datasetName","confirmRelink","warn","log","Error","String","currentDataset","newDataset","validate","response","toLowerCase","trim"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,KAAK,QAAO,sBAAqB;AAEzC,SAAQC,gBAAgB,QAAO,+CAA8C;AAC7E,SAAQC,wBAAwB,QAAO,uDAAsD;AAC7F,SAAQC,mBAAmB,QAAO,kDAAiD;AACnF,SAAQC,yBAAyB,QAAO,gDAA+C;AACvF,SAAQC,gBAAgB,QAAO,uCAAsC;AACrE,SAAQC,aAAa,QAAO,oCAAmC;AAC/D,SAAQC,WAAW,EAAEC,WAAW,QAAO,sCAAqC;AAC5E,SAAQC,YAAY,QAAO,gCAA+B;AAC1D,SAAQC,gBAAgB,QAAO,+BAA8B;AAE7D,MAAMC,iBAAiBZ,SAAS;AAEhC,OAAO,MAAMa,yBAAyBd;IACpC,OAAgBe,OAAO;QACrBC,WAAWlB,KAAKmB,MAAM,CAAC;YACrBC,aAAa;YACbC,UAAU;QACZ;QACAC,eAAetB,KAAKmB,MAAM,CAAC;YACzBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,mDAAkD;IAEhF,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,GAAGX,iBAAiB;YAClBM,aAAa;YACbM,WAAW;QACb,EAAE;QACFC,OAAO1B,MAAM2B,OAAO,CAAC;YACnBR,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBQ,gBAA0B;QAAC;KAAqB,CAAA;IAEhE,MAAaC,MAAqB;QAChC,MAAM,EAACb,IAAI,EAAEQ,KAAK,EAAC,GAAG,MAAM,IAAI,CAACM,KAAK,CAACf;QACvC,MAAM,EAACW,KAAK,EAAC,GAAGF;QAEhB,MAAMO,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRzB,iBAAiB;oBACf0B,qBAAqB;wBACnB;4BAACC,OAAO;4BAAQC,YAAY;wBAAyB;wBACrD;4BAACD,OAAO;4BAAUC,YAAY;wBAAyB;qBACxD;gBACH;QACJ;QAEA,IAAIpB,KAAKC,SAAS,EAAE;YAClB,MAAM,EAACoB,OAAO,EAAC,GAAGjC,iBAAiBY,KAAKC,SAAS;YACjD,MAAMqB,YAAYjC,yBAAyBgC;YAC3C,IAAIC,WAAW;gBACb,IAAI,CAACC,KAAK,CAACD,WAAW;oBAACE,MAAM;gBAAC;YAChC;QACF;QAEA,IAAIxB,KAAKK,aAAa,EAAE;YACtB,MAAMoB,aAAanC,oBAAoBU,KAAKK,aAAa;YACzD,IAAIoB,YAAY;gBACd,IAAI,CAACF,KAAK,CAACE,YAAY;oBAACD,MAAM;gBAAC;YACjC;QACF;QAEA,IAAI;YACF,MAAM,CAACE,kBAAkBC,QAAQ,GAAG,MAAMC,QAAQC,GAAG,CAAC;gBACpDjC,aAAamB;gBACbrB,YAAYqB;aACb;YAED,MAAMe,WAAWJ,iBAAiBK,GAAG,CAAC,CAACC,KAAOA,GAAGC,IAAI;YAErD,MAAMC,iBAAiBlC,KAAKC,SAAS,IAAK,MAAMV;YAEhD,MAAM,EAAC8B,OAAO,EAAEc,WAAW,EAAC,GAAG/C,iBAAiB8C;YAEhD,MAAME,gBAAgBT,QAAQU,IAAI,CAAC,CAACC,QAAUA,MAAML,IAAI,KAAKZ;YAC7D,IAAI,CAACe,eAAe;gBAClB,MAAMG,mBAAmBZ,QAAQI,GAAG,CAAC,CAACS,IAAM,CAAC,CAAC,EAAEA,EAAEP,IAAI,EAAE,EAAEQ,IAAI,CAAC;gBAC/D,IAAI,CAAClB,KAAK,CACR,CAAC,eAAe,EAAEY,YAAY,qCAAqC,EAAEI,kBAAkB,EACvF;oBAACf,MAAM;gBAAC;YAEZ;YAEA,MAAMnB,gBACJL,KAAKK,aAAa,IACjByB,CAAAA,SAASY,MAAM,GAAG,IACf,MAAMjD,cAAcqC,UAAU;gBAC5Ba,SAAS;YACX,KACA,IAAG;YAET,IAAI,CAACtC,eAAe;gBAClB,IAAI,CAACkB,KAAK,CAAC,oCAAoC;oBAACC,MAAM;gBAAC;YACzD;YAEA,IAAI,CAACM,SAASc,QAAQ,CAACvC,gBAAgB;gBACrC,IAAI,CAACkB,KAAK,CACR,CAAC,SAAS,EAAElB,cAAc,sCAAsC,EAAEyB,SAASW,IAAI,CAAC,OAAO,EACvF;oBAACjB,MAAM;gBAAC;YAEZ;YAEA,IAAIY,cAAcS,WAAW,KAAKxC,eAAe;gBAC/C,IAAI,CAACkB,KAAK,CAAC,CAAC,cAAc,EAAEY,YAAY,mBAAmB,EAAE9B,eAAe,EAAE;oBAACmB,MAAM;gBAAC;YACxF;YAEA,IAAIY,cAAcS,WAAW,IAAI,CAACnC,OAAO;gBACvC,MAAM,IAAI,CAACoC,aAAa,CAACV,cAAcS,WAAW,EAAExC;YACtD,OAAO,IAAIK,SAAS0B,cAAcS,WAAW,EAAE;gBAC7C,IAAI,CAACE,IAAI,CAAC,CAAC,wDAAwD,EAAE1C,eAAe;YACtF;YAEA,MAAMV,YAAYoB,WAAWM,SAAShB;YAEtC,IAAI,CAAC2C,GAAG,CAAC,CAAC,cAAc,EAAEb,YAAY,WAAW,EAAE9B,cAAc,aAAa,CAAC;QACjF,EAAE,OAAOkB,OAAO;YACdzB,eAAe,CAAC,2BAA2B,CAAC,EAAEyB;YAC9C,IAAI,CAACA,KAAK,CACR,CAAC,8BAA8B,EAAEA,iBAAiB0B,QAAQ1B,MAAMoB,OAAO,GAAGO,OAAO3B,QAAQ,EACzF;gBAACC,MAAM;YAAC;QAEZ;IACF;IAEA,MAAcsB,cAAcK,cAAsB,EAAEC,UAAkB,EAAiB;QACrF,MAAMjE,MAAM;YACVwD,SAAS,CAAC,iCAAiC,EAAEQ,eAAe,kEAAkE,EAAEC,WAAW,iBAAiB,CAAC;YAC7JC,UAAU,CAAClE;gBACT,MAAMmE,WAAWnE,MAAMoE,WAAW,GAAGC,IAAI;gBACzC,OAAOF,aAAa,SAAS;YAC/B;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../src/commands/datasets/alias/link.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input} from '@sanity/cli-core/ux'\n\nimport {processAliasName} from '../../../actions/dataset/processAliasName.js'\nimport {validateDatasetAliasName} from '../../../actions/dataset/validateDatasetAliasName.js'\nimport {validateDatasetName} from '../../../actions/dataset/validateDatasetName.js'\nimport {promptForDatasetAliasName} from '../../../prompts/promptForDatasetAliasName.js'\nimport {promptForProject} from '../../../prompts/promptForProject.js'\nimport {selectDataset} from '../../../prompts/selectDataset.js'\nimport {listAliases, updateAlias} from '../../../services/datasetAliases.js'\nimport {listDatasets} from '../../../services/datasets.js'\nimport {formatCliErrorMessages} from '../../../util/formatCliErrorMessages.js'\nimport {getProjectIdFlag} from '../../../util/sharedFlags.js'\n\nconst linkAliasDebug = subdebug('dataset:alias:link')\n\nexport class LinkAliasCommand extends SanityCommand<typeof LinkAliasCommand> {\n static override args = {\n aliasName: Args.string({\n description: 'Dataset alias name to link',\n required: false,\n }),\n targetDataset: Args.string({\n description: 'Target dataset name to link the alias to',\n required: false,\n }),\n }\n\n static override description = 'Link a dataset alias to a dataset in the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Link an alias with interactive prompts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference',\n description: 'Link alias named \"conference\" with interactive dataset selection',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025',\n description: 'Link alias \"conference\" to \"conf-2025\" dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> conference conf-2025 --force',\n description: 'Force link without confirmation (skip relink prompt)',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to link dataset alias in',\n semantics: 'override',\n }),\n force: Flags.boolean({\n description: 'Skip confirmation prompt when relinking existing alias',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:alias:link']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(LinkAliasCommand)\n const {force} = flags\n\n if (this.isUnattended()) {\n const errors: string[] = []\n\n if (!args.aliasName) {\n errors.push('Dataset alias name is required. Pass it as the `<aliasName>` argument.')\n }\n if (!args.targetDataset) {\n errors.push('Target dataset is required. Pass it as the `<targetDataset>` argument.')\n }\n\n if (errors.length > 0) {\n this.error(formatCliErrorMessages(errors), {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n if (args.aliasName) {\n const {apiName} = processAliasName(args.aliasName)\n const nameError = validateDatasetAliasName(apiName)\n if (nameError) {\n this.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n if (args.targetDataset) {\n const datasetErr = validateDatasetName(args.targetDataset)\n if (datasetErr) {\n this.error(datasetErr, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n try {\n const [datasetsResponse, aliases] = await Promise.all([\n listDatasets(projectId),\n listAliases(projectId),\n ])\n\n const datasets = datasetsResponse.map((ds) => ds.name)\n\n const aliasNameInput = args.aliasName || (await promptForDatasetAliasName())\n\n const {apiName, displayName} = processAliasName(aliasNameInput)\n\n const existingAlias = aliases.find((alias) => alias.name === apiName)\n if (!existingAlias) {\n const availableAliases = aliases.map((a) => `~${a.name}`).join(', ')\n this.error(\n `Dataset alias \"${displayName}\" does not exist. Available aliases: ${availableAliases}`,\n {exit: 1},\n )\n }\n\n const targetDataset =\n args.targetDataset ||\n (datasets.length > 0\n ? await selectDataset(datasets, {\n message: 'Select target dataset to link alias to:',\n })\n : null)\n\n if (!targetDataset) {\n this.error('No datasets available to link to', {exit: 1})\n }\n\n if (!datasets.includes(targetDataset)) {\n this.error(\n `Dataset \"${targetDataset}\" does not exist. Available datasets: ${datasets.join(', ')}`,\n {exit: 1},\n )\n }\n\n if (existingAlias.datasetName === targetDataset) {\n this.error(`Dataset alias ${displayName} already linked to ${targetDataset}`, {exit: 1})\n }\n\n if (existingAlias.datasetName && !force) {\n if (this.isUnattended()) {\n this.error('Relinking a dataset alias requires confirmation. Re-run with `--force`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n await this.confirmRelink(existingAlias.datasetName, targetDataset)\n } else if (force && existingAlias.datasetName) {\n this.warn(`'--force' used: skipping confirmation, linking alias to ${targetDataset}`)\n }\n\n await updateAlias(projectId, apiName, targetDataset)\n\n this.log(`Dataset alias ${displayName} linked to ${targetDataset} successfully`)\n } catch (error) {\n if (error instanceof CLIError) throw error\n linkAliasDebug(`Error linking dataset alias`, error)\n this.error(\n `Dataset alias linking failed: ${error instanceof Error ? error.message : String(error)}`,\n {exit: 1},\n )\n }\n }\n\n private async confirmRelink(currentDataset: string, newDataset: string): Promise<void> {\n await input({\n message: `This alias is linked to dataset <${currentDataset}>. Are you ABSOLUTELY sure you want to link this dataset alias to ${newDataset}?\\n Type YES/NO:`,\n validate: (input) => {\n const response = input.toLowerCase().trim()\n return response === 'yes' || 'Type YES to confirm or Ctrl + C to cancel dataset alias link.'\n },\n })\n }\n}\n"],"names":["Args","Flags","CLIError","exitCodes","SanityCommand","subdebug","input","processAliasName","validateDatasetAliasName","validateDatasetName","promptForDatasetAliasName","promptForProject","selectDataset","listAliases","updateAlias","listDatasets","formatCliErrorMessages","getProjectIdFlag","linkAliasDebug","LinkAliasCommand","args","aliasName","string","description","required","targetDataset","examples","command","flags","semantics","force","boolean","hiddenAliases","run","parse","isUnattended","errors","push","length","error","exit","USAGE_ERROR","apiName","nameError","datasetErr","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasetsResponse","aliases","Promise","all","datasets","map","ds","name","aliasNameInput","displayName","existingAlias","find","alias","availableAliases","a","join","message","includes","datasetName","confirmRelink","warn","log","Error","String","currentDataset","newDataset","validate","response","toLowerCase","trim"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import { SanityCommand, subdebug } from '@sanity/cli-core';
2
+ import { CLIError } from '@oclif/core/errors';
3
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
4
  import { input } from '@sanity/cli-core/ux';
4
5
  import { processAliasName } from '../../../actions/dataset/processAliasName.js';
5
6
  import { validateDatasetAliasName } from '../../../actions/dataset/validateDatasetAliasName.js';
@@ -46,6 +47,20 @@ export class UnlinkAliasCommand extends SanityCommand {
46
47
  async run() {
47
48
  const { args, flags } = await this.parse(UnlinkAliasCommand);
48
49
  const { force } = flags;
50
+ if (!args.aliasName && this.isUnattended()) {
51
+ this.error('Dataset alias name is required. Pass it as the `<aliasName>` argument.', {
52
+ exit: exitCodes.USAGE_ERROR
53
+ });
54
+ }
55
+ if (args.aliasName) {
56
+ const { apiName } = processAliasName(args.aliasName);
57
+ const nameError = validateDatasetAliasName(apiName);
58
+ if (nameError) {
59
+ this.error(nameError, {
60
+ exit: exitCodes.USAGE_ERROR
61
+ });
62
+ }
63
+ }
49
64
  const projectId = await this.getProjectId({
50
65
  fallback: ()=>promptForProject({
51
66
  requiredPermissions: [
@@ -66,7 +81,7 @@ export class UnlinkAliasCommand extends SanityCommand {
66
81
  const nameError = validateDatasetAliasName(apiName);
67
82
  if (nameError) {
68
83
  this.error(nameError, {
69
- exit: 1
84
+ exit: exitCodes.USAGE_ERROR
70
85
  });
71
86
  }
72
87
  const aliases = await listAliases(projectId);
@@ -85,11 +100,17 @@ export class UnlinkAliasCommand extends SanityCommand {
85
100
  if (force) {
86
101
  this.warn(`'--force' used: skipping confirmation, unlinking alias "${displayName}"`);
87
102
  } else {
103
+ if (this.isUnattended()) {
104
+ this.error('Unlinking a dataset alias requires confirmation. Re-run with `--force`.', {
105
+ exit: exitCodes.USAGE_ERROR
106
+ });
107
+ }
88
108
  await this.confirmUnlink(linkedAlias.datasetName);
89
109
  }
90
110
  const result = await unlinkAlias(projectId, apiName);
91
111
  this.log(`Dataset alias ${displayName} unlinked from ${result.datasetName} successfully`);
92
112
  } catch (error) {
113
+ if (error instanceof CLIError) throw error;
93
114
  unlinkAliasDebug('Error unlinking dataset alias', error);
94
115
  this.error(`Dataset alias unlink failed: ${error instanceof Error ? error.message : String(error)}`, {
95
116
  exit: 1