@sanity/cli 7.18.0 → 8.0.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 (131) hide show
  1. package/README.md +74 -4
  2. package/dist/SanityHelp.js +1 -35
  3. package/dist/SanityHelp.js.map +1 -1
  4. package/dist/actions/assets/assetFileError.js +9 -0
  5. package/dist/actions/assets/assetFileError.js.map +1 -0
  6. package/dist/actions/assets/uploadAssetFromFile.js +40 -0
  7. package/dist/actions/assets/uploadAssetFromFile.js.map +1 -0
  8. package/dist/actions/assets/uploadAssetWithProgress.js +76 -0
  9. package/dist/actions/assets/uploadAssetWithProgress.js.map +1 -0
  10. package/dist/actions/deploy/deployApp.js +39 -44
  11. package/dist/actions/deploy/deployApp.js.map +1 -1
  12. package/dist/actions/deploy/deployChecks.js +21 -13
  13. package/dist/actions/deploy/deployChecks.js.map +1 -1
  14. package/dist/actions/deploy/deployRunner.js +8 -7
  15. package/dist/actions/deploy/deployRunner.js.map +1 -1
  16. package/dist/actions/deploy/deployStudio.js +55 -35
  17. package/dist/actions/deploy/deployStudio.js.map +1 -1
  18. package/dist/actions/deploy/deploymentPlan.js +17 -29
  19. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  20. package/dist/actions/deploy/resolveDeployTarget.js +2 -8
  21. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  22. package/dist/actions/dev/servers/getDevServerConfig.js +2 -8
  23. package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
  24. package/dist/actions/dev/servers/startStudioDevServer.js +7 -1
  25. package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
  26. package/dist/actions/init/bootstrapRemoteTemplate.js +2 -2
  27. package/dist/actions/init/bootstrapRemoteTemplate.js.map +1 -1
  28. package/dist/actions/schema/listSchemas.js +1 -1
  29. package/dist/actions/schema/listSchemas.js.map +1 -1
  30. package/dist/actions/tokens/constants.js +2 -2
  31. package/dist/actions/tokens/constants.js.map +1 -1
  32. package/dist/actions/tokens/expiry.js +35 -0
  33. package/dist/actions/tokens/expiry.js.map +1 -0
  34. package/dist/actions/tokens/types.js.map +1 -1
  35. package/dist/actions/tokens/validateRole.js +5 -2
  36. package/dist/actions/tokens/validateRole.js.map +1 -1
  37. package/dist/actions/typegen/count.js +6 -0
  38. package/dist/actions/typegen/count.js.map +1 -0
  39. package/dist/actions/typegen/formatPath.js +5 -0
  40. package/dist/actions/typegen/formatPath.js.map +1 -0
  41. package/dist/actions/typegen/percent.js +8 -0
  42. package/dist/actions/typegen/percent.js.map +1 -0
  43. package/dist/actions/typegen/renderTypegenProgress.js +88 -0
  44. package/dist/actions/typegen/renderTypegenProgress.js.map +1 -0
  45. package/dist/actions/undeploy/adapters.js +6 -9
  46. package/dist/actions/undeploy/adapters.js.map +1 -1
  47. package/dist/actions/undeploy/runUndeploy.js +12 -4
  48. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  49. package/dist/actions/undeploy/undeployPlan.js +6 -14
  50. package/dist/actions/undeploy/undeployPlan.js.map +1 -1
  51. package/dist/commands/assets/upload.js +126 -0
  52. package/dist/commands/assets/upload.js.map +1 -0
  53. package/dist/commands/backups/list.js +1 -1
  54. package/dist/commands/backups/list.js.map +1 -1
  55. package/dist/commands/datasets/copy.js +1 -1
  56. package/dist/commands/datasets/copy.js.map +1 -1
  57. package/dist/commands/login.js +2 -8
  58. package/dist/commands/login.js.map +1 -1
  59. package/dist/commands/mcp/configure.js.map +1 -1
  60. package/dist/commands/migrations/list.js +1 -1
  61. package/dist/commands/migrations/list.js.map +1 -1
  62. package/dist/commands/migrations/run.js +67 -3
  63. package/dist/commands/migrations/run.js.map +1 -1
  64. package/dist/commands/new.js +4 -3
  65. package/dist/commands/new.js.map +1 -1
  66. package/dist/commands/organizations/list.js +1 -1
  67. package/dist/commands/organizations/list.js.map +1 -1
  68. package/dist/commands/projects/list.js +39 -12
  69. package/dist/commands/projects/list.js.map +1 -1
  70. package/dist/commands/projects/unclaimed.js +39 -33
  71. package/dist/commands/projects/unclaimed.js.map +1 -1
  72. package/dist/commands/tokens/create.js +92 -7
  73. package/dist/commands/tokens/create.js.map +1 -1
  74. package/dist/commands/tokens/delete.js +2 -2
  75. package/dist/commands/tokens/delete.js.map +1 -1
  76. package/dist/commands/tokens/list.js +12 -11
  77. package/dist/commands/tokens/list.js.map +1 -1
  78. package/dist/commands/tokens/rotate.js +95 -0
  79. package/dist/commands/tokens/rotate.js.map +1 -0
  80. package/dist/commands/typegen/generate.js +222 -0
  81. package/dist/commands/typegen/generate.js.map +1 -0
  82. package/dist/commands/users/list.js +8 -8
  83. package/dist/commands/users/list.js.map +1 -1
  84. package/dist/exports/_internal.d.ts +29 -0
  85. package/dist/exports/_internal.js +1 -0
  86. package/dist/exports/_internal.js.map +1 -1
  87. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
  88. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  89. package/dist/exports/invokeSanityCli/help.js +4 -0
  90. package/dist/exports/invokeSanityCli/help.js.map +1 -1
  91. package/dist/exports/invokeSanityCli/index.js +2 -0
  92. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  93. package/dist/hooks/commandNotFound/topicAliases.js +13 -40
  94. package/dist/hooks/commandNotFound/topicAliases.js.map +1 -1
  95. package/dist/hooks/prerun/setupTelemetry.js +3 -2
  96. package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
  97. package/dist/server/vite/plugin-typegen.js +4 -16
  98. package/dist/server/vite/plugin-typegen.js.map +1 -1
  99. package/dist/services/assets.js +46 -0
  100. package/dist/services/assets.js.map +1 -0
  101. package/dist/services/tokens.js +81 -31
  102. package/dist/services/tokens.js.map +1 -1
  103. package/dist/topicAliases.js +43 -0
  104. package/dist/topicAliases.js.map +1 -1
  105. package/dist/util/parseArguments.js +7 -2
  106. package/dist/util/parseArguments.js.map +1 -1
  107. package/dist/util/readTokenFromStdin.js +17 -0
  108. package/dist/util/readTokenFromStdin.js.map +1 -0
  109. package/dist/util/responsiveTable.js +97 -0
  110. package/dist/util/responsiveTable.js.map +1 -0
  111. package/dist/util/telemetry/commandTelemetry.js +34 -0
  112. package/dist/util/telemetry/commandTelemetry.js.map +1 -0
  113. package/dist/util/unclaimedProjects.js +10 -0
  114. package/dist/util/unclaimedProjects.js.map +1 -1
  115. package/oclif.config.js +2 -4
  116. package/oclif.manifest.json +213 -1
  117. package/package.json +12 -10
  118. package/templates/shopify/components/inputs/ShopifyMetafield.tsx +20 -0
  119. package/templates/shopify/docs/features.md +24 -0
  120. package/templates/shopify/schemaTypes/index.ts +2 -0
  121. package/templates/shopify/schemaTypes/objects/shopify/shopifyCollectionType.ts +18 -1
  122. package/templates/shopify/schemaTypes/objects/shopify/shopifyMetafieldType.ts +47 -0
  123. package/templates/shopify/schemaTypes/objects/shopify/shopifyProductType.ts +17 -0
  124. package/templates/shopify/utils/formatMetafieldValue.ts +30 -0
  125. package/templates/shopify-online-storefront/components/inputs/ShopifyMetafield.tsx +22 -0
  126. package/templates/shopify-online-storefront/schemaTypes/index.ts +4 -0
  127. package/templates/shopify-online-storefront/schemaTypes/objects/shop.ts +16 -0
  128. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollection.ts +19 -0
  129. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyMetafield.ts +53 -0
  130. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyProduct.ts +19 -0
  131. package/templates/shopify-online-storefront/utils/formatMetafieldValue.ts +30 -0
@@ -0,0 +1,95 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { isHttpError } from '@sanity/client';
5
+ import { rotateToken } from '../../services/tokens.js';
6
+ import { readTokenFromStdin } from '../../util/readTokenFromStdin.js';
7
+ const tokensRotateDebug = subdebug('tokens:rotate');
8
+ const TOKEN_USAGE_HINT = 'Token is required. Pipe it on standard input (`echo "$SANITY_TOKEN" | sanity tokens rotate`) to keep it out of shell history, or pass it with `--token`.';
9
+ export class RotateTokenCommand extends SanityCommand {
10
+ static description = 'Rotate an API token, replacing its secret with a new one';
11
+ static examples = [
12
+ {
13
+ command: 'echo "$SANITY_TOKEN" | <%= config.bin %> <%= command.id %>',
14
+ description: 'Rotate the token piped on standard input'
15
+ },
16
+ {
17
+ command: '<%= config.bin %> <%= command.id %> < token.txt',
18
+ description: 'Rotate a token read from a file'
19
+ },
20
+ {
21
+ command: 'echo "$SANITY_TOKEN" | <%= config.bin %> <%= command.id %> --json',
22
+ description: 'Output the rotated token as JSON'
23
+ }
24
+ ];
25
+ static flags = {
26
+ json: Flags.boolean({
27
+ default: false,
28
+ description: 'Output as JSON'
29
+ }),
30
+ token: Flags.string({
31
+ char: 't',
32
+ description: 'Token to rotate (prefer standard input to keep it out of shell history)',
33
+ helpValue: '<token>'
34
+ })
35
+ };
36
+ static hiddenAliases = [
37
+ 'token:rotate'
38
+ ];
39
+ async run() {
40
+ const { flags } = await this.parse(RotateTokenCommand);
41
+ const { json } = flags;
42
+ const token = flags.token?.trim() || await this.readTokenArg();
43
+ try {
44
+ tokensRotateDebug('Rotating API token');
45
+ const robot = await rotateToken(token);
46
+ if (json) {
47
+ this.log(JSON.stringify(robot, null, 2));
48
+ return;
49
+ }
50
+ this.log('API token rotated');
51
+ this.log(`Label: ${robot.label}`);
52
+ this.log(`ID: ${robot.id}`);
53
+ if (robot.expiresAt) {
54
+ this.log(`Expires: ${robot.expiresAt}`);
55
+ }
56
+ this.log(`Token: ${robot.token}`);
57
+ this.log('');
58
+ this.log("Copy the token now. It won't be shown again.");
59
+ this.log('The previous token was revoked and no longer works.');
60
+ } catch (error) {
61
+ tokensRotateDebug('Error rotating token', error);
62
+ if (isHttpError(error) && error.statusCode === 401) {
63
+ this.error('Token is invalid, expired, or was already rotated or revoked. Check that you are passing the current token.', {
64
+ exit: exitCodes.RUNTIME_ERROR
65
+ });
66
+ }
67
+ if (isHttpError(error) && error.statusCode === 403) {
68
+ this.error('The token is not an API token and cannot be rotated. Personal tokens are renewed by logging in again.', {
69
+ exit: exitCodes.RUNTIME_ERROR
70
+ });
71
+ }
72
+ this.error(`Token rotation failed:\n${getErrorMessage(error)}`, {
73
+ exit: exitCodes.RUNTIME_ERROR
74
+ });
75
+ }
76
+ }
77
+ async readTokenArg() {
78
+ let token;
79
+ try {
80
+ token = await readTokenFromStdin(TOKEN_USAGE_HINT);
81
+ } catch (error) {
82
+ return this.error(getErrorMessage(error), {
83
+ exit: exitCodes.USAGE_ERROR
84
+ });
85
+ }
86
+ if (!token) {
87
+ this.error(TOKEN_USAGE_HINT, {
88
+ exit: exitCodes.USAGE_ERROR
89
+ });
90
+ }
91
+ return token;
92
+ }
93
+ }
94
+
95
+ //# sourceMappingURL=rotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/tokens/rotate.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {rotateToken} from '../../services/tokens.js'\nimport {readTokenFromStdin} from '../../util/readTokenFromStdin.js'\n\nconst tokensRotateDebug = subdebug('tokens:rotate')\n\nconst TOKEN_USAGE_HINT =\n 'Token is required. Pipe it on standard input (`echo \"$SANITY_TOKEN\" | sanity tokens rotate`) to keep it out of shell history, or pass it with `--token`.'\n\nexport class RotateTokenCommand extends SanityCommand<typeof RotateTokenCommand> {\n static override description = 'Rotate an API token, replacing its secret with a new one'\n\n static override examples = [\n {\n command: 'echo \"$SANITY_TOKEN\" | <%= config.bin %> <%= command.id %>',\n description: 'Rotate the token piped on standard input',\n },\n {\n command: '<%= config.bin %> <%= command.id %> < token.txt',\n description: 'Rotate a token read from a file',\n },\n {\n command: 'echo \"$SANITY_TOKEN\" | <%= config.bin %> <%= command.id %> --json',\n description: 'Output the rotated token as JSON',\n },\n ]\n\n static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output as JSON',\n }),\n token: Flags.string({\n char: 't',\n description: 'Token to rotate (prefer standard input to keep it out of shell history)',\n helpValue: '<token>',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:rotate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(RotateTokenCommand)\n const {json} = flags\n\n const token = flags.token?.trim() || (await this.readTokenArg())\n\n try {\n tokensRotateDebug('Rotating API token')\n const robot = await rotateToken(token)\n\n if (json) {\n this.log(JSON.stringify(robot, null, 2))\n return\n }\n\n this.log('API token rotated')\n this.log(`Label: ${robot.label}`)\n this.log(`ID: ${robot.id}`)\n if (robot.expiresAt) {\n this.log(`Expires: ${robot.expiresAt}`)\n }\n this.log(`Token: ${robot.token}`)\n this.log('')\n this.log(\"Copy the token now. It won't be shown again.\")\n this.log('The previous token was revoked and no longer works.')\n } catch (error) {\n tokensRotateDebug('Error rotating token', error)\n\n if (isHttpError(error) && error.statusCode === 401) {\n this.error(\n 'Token is invalid, expired, or was already rotated or revoked. Check that you are passing the current token.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n if (isHttpError(error) && error.statusCode === 403) {\n this.error(\n 'The token is not an API token and cannot be rotated. Personal tokens are renewed by logging in again.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n this.error(`Token rotation failed:\\n${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async readTokenArg(): Promise<string> {\n let token: string\n try {\n token = await readTokenFromStdin(TOKEN_USAGE_HINT)\n } catch (error) {\n return this.error(getErrorMessage(error), {exit: exitCodes.USAGE_ERROR})\n }\n\n if (!token) {\n this.error(TOKEN_USAGE_HINT, {exit: exitCodes.USAGE_ERROR})\n }\n\n return token\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","rotateToken","readTokenFromStdin","tokensRotateDebug","TOKEN_USAGE_HINT","RotateTokenCommand","description","examples","command","flags","json","boolean","default","token","string","char","helpValue","hiddenAliases","run","parse","trim","readTokenArg","robot","log","JSON","stringify","label","id","expiresAt","error","statusCode","exit","RUNTIME_ERROR","USAGE_ERROR"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,WAAW,QAAO,2BAA0B;AACpD,SAAQC,kBAAkB,QAAO,mCAAkC;AAEnE,MAAMC,oBAAoBL,SAAS;AAEnC,MAAMM,mBACJ;AAEF,OAAO,MAAMC,2BAA2BR;IACtC,OAAgBS,cAAc,2DAA0D;IAExF,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;QACtBC,MAAMf,MAAMgB,OAAO,CAAC;YAClBC,SAAS;YACTN,aAAa;QACf;QACAO,OAAOlB,MAAMmB,MAAM,CAAC;YAClBC,MAAM;YACNT,aAAa;YACbU,WAAW;QACb;IACF,EAAC;IAED,OAAgBC,gBAA0B;QAAC;KAAe,CAAA;IAE1D,MAAaC,MAAqB;QAChC,MAAM,EAACT,KAAK,EAAC,GAAG,MAAM,IAAI,CAACU,KAAK,CAACd;QACjC,MAAM,EAACK,IAAI,EAAC,GAAGD;QAEf,MAAMI,QAAQJ,MAAMI,KAAK,EAAEO,UAAW,MAAM,IAAI,CAACC,YAAY;QAE7D,IAAI;YACFlB,kBAAkB;YAClB,MAAMmB,QAAQ,MAAMrB,YAAYY;YAEhC,IAAIH,MAAM;gBACR,IAAI,CAACa,GAAG,CAACC,KAAKC,SAAS,CAACH,OAAO,MAAM;gBACrC;YACF;YAEA,IAAI,CAACC,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC,CAAC,OAAO,EAAED,MAAMI,KAAK,EAAE;YAChC,IAAI,CAACH,GAAG,CAAC,CAAC,IAAI,EAAED,MAAMK,EAAE,EAAE;YAC1B,IAAIL,MAAMM,SAAS,EAAE;gBACnB,IAAI,CAACL,GAAG,CAAC,CAAC,SAAS,EAAED,MAAMM,SAAS,EAAE;YACxC;YACA,IAAI,CAACL,GAAG,CAAC,CAAC,OAAO,EAAED,MAAMT,KAAK,EAAE;YAChC,IAAI,CAACU,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC;QACX,EAAE,OAAOM,OAAO;YACd1B,kBAAkB,wBAAwB0B;YAE1C,IAAI7B,YAAY6B,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CACR,+GACA;oBAACE,MAAMnC,UAAUoC,aAAa;gBAAA;YAElC;YACA,IAAIhC,YAAY6B,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CACR,yGACA;oBAACE,MAAMnC,UAAUoC,aAAa;gBAAA;YAElC;YAEA,IAAI,CAACH,KAAK,CAAC,CAAC,wBAAwB,EAAE9B,gBAAgB8B,QAAQ,EAAE;gBAC9DE,MAAMnC,UAAUoC,aAAa;YAC/B;QACF;IACF;IAEA,MAAcX,eAAgC;QAC5C,IAAIR;QACJ,IAAI;YACFA,QAAQ,MAAMX,mBAAmBE;QACnC,EAAE,OAAOyB,OAAO;YACd,OAAO,IAAI,CAACA,KAAK,CAAC9B,gBAAgB8B,QAAQ;gBAACE,MAAMnC,UAAUqC,WAAW;YAAA;QACxE;QAEA,IAAI,CAACpB,OAAO;YACV,IAAI,CAACgB,KAAK,CAACzB,kBAAkB;gBAAC2B,MAAMnC,UAAUqC,WAAW;YAAA;QAC3D;QAEA,OAAOpB;IACT;AACF"}
@@ -0,0 +1,222 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { styleText } from 'node:util';
3
+ import { Flags } from '@oclif/core';
4
+ import { CLIError } from '@oclif/core/errors';
5
+ import { SanityCommand } from '@sanity/cli-core';
6
+ import { spinner } from '@sanity/cli-core/ux';
7
+ import { configDefinition, readConfig, runTypegenGenerate, runTypegenWatcher, TypegenWatchModeTrace, TypesGeneratedTrace } from '@sanity/codegen';
8
+ import omit from 'lodash-es/omit.js';
9
+ import once from 'lodash-es/once.js';
10
+ import { createTypegenProgressRenderer } from '../../actions/typegen/renderTypegenProgress.js';
11
+ const description = `Sanity TypeGen
12
+
13
+ ${styleText('bold', 'Configuration:')}
14
+ This command can utilize configuration settings defined in a \`sanity-typegen.json\` file. These settings include:
15
+
16
+ - "path": Specifies a glob pattern to locate your TypeScript or JavaScript files.
17
+ Default: "./src/**/*.{ts,tsx,js,jsx}"
18
+
19
+ - "schema": Defines the path to your Sanity schema file. This file should be generated using the \`sanity schema extract\` command.
20
+ Default: "schema.json"
21
+
22
+ - "generates": Indicates the path where the generated TypeScript type definitions will be saved.
23
+ Default: "./sanity.types.ts"
24
+
25
+ The default configuration values listed above are used if not overridden in your \`sanity-typegen.json\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.
26
+
27
+ ${styleText('bold', 'Note:')}
28
+ - The \`sanity schema extract\` command is a prerequisite for extracting your Sanity Studio schema into a \`schema.json\` file, which is then used by the \`sanity typegen generate\` command to generate type definitions.`.trim();
29
+ export class TypegenGenerateCommand extends SanityCommand {
30
+ static description = description;
31
+ static examples = [
32
+ {
33
+ command: '<%= config.bin %> <%= command.id %>',
34
+ description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \`sanity schema extract\` command.`
35
+ }
36
+ ];
37
+ static flags = {
38
+ 'config-path': Flags.string({
39
+ description: '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.'
40
+ }),
41
+ watch: Flags.boolean({
42
+ default: false,
43
+ description: '[Default: false] Run the typegen in watch mode'
44
+ })
45
+ };
46
+ static hiddenAliases = [
47
+ 'typegen:generate'
48
+ ];
49
+ async run() {
50
+ const { flags } = await this.parse(TypegenGenerateCommand);
51
+ if (flags.watch) {
52
+ await this.runWatcher();
53
+ return;
54
+ }
55
+ await this.runSingle();
56
+ }
57
+ async getConfig() {
58
+ const spin = spinner({}).start('Loading config…');
59
+ try {
60
+ const { flags } = await this.parse(TypegenGenerateCommand);
61
+ const rootDir = await this.getProjectRoot();
62
+ const config = await this.getCliConfig();
63
+ const configPath = flags['config-path'];
64
+ const workDir = rootDir.directory;
65
+ const legacyConfigPath = configPath || 'sanity-typegen.json';
66
+ let hasLegacyConfig = false;
67
+ try {
68
+ const file = await stat(legacyConfigPath);
69
+ hasLegacyConfig = file.isFile();
70
+ } catch (err) {
71
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {
72
+ spin.fail();
73
+ this.error(`Typegen config file not found: ${configPath}`, {
74
+ exit: 1
75
+ });
76
+ }
77
+ if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {
78
+ spin.fail();
79
+ this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {
80
+ exit: 1
81
+ });
82
+ }
83
+ }
84
+ if (config?.typegen && hasLegacyConfig) {
85
+ spin.warn(styleText('yellow', `You've specified typegen in your Sanity CLI config, but also have a typegen config.
86
+
87
+ The config from the Sanity CLI config is used.
88
+ `));
89
+ return {
90
+ config: configDefinition.parse(config.typegen || {}),
91
+ path: rootDir.path,
92
+ type: 'cli',
93
+ workDir
94
+ };
95
+ }
96
+ if (hasLegacyConfig) {
97
+ spin.warn(styleText('yellow', `The separate typegen config has been deprecated. Use \`typegen\` in the sanity CLI config instead.
98
+
99
+ See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`));
100
+ return {
101
+ config: await readConfig(legacyConfigPath),
102
+ path: legacyConfigPath,
103
+ type: 'legacy',
104
+ workDir
105
+ };
106
+ }
107
+ spin.succeed(`Config loaded from sanity.cli.ts`);
108
+ return {
109
+ config: configDefinition.parse(config.typegen || {}),
110
+ path: rootDir.path,
111
+ type: 'cli',
112
+ workDir
113
+ };
114
+ } catch (err) {
115
+ // The config-file checks above already reported a user-facing error via
116
+ // `this.error()` (an oclif CLIError). Re-throw those as-is instead of
117
+ // wrapping them a second time and failing the spinner twice.
118
+ if (err instanceof CLIError) throw err;
119
+ spin.fail();
120
+ this.error(`An error occurred during config loading: ${err}`, {
121
+ exit: 1
122
+ });
123
+ }
124
+ }
125
+ async runSingle() {
126
+ const trace = this.telemetry.trace(TypesGeneratedTrace);
127
+ let spin;
128
+ try {
129
+ const { config: typegenConfig, type: typegenConfigMethod, workDir } = await this.getConfig();
130
+ trace.start();
131
+ spin = spinner({}).start('Loading schema…');
132
+ const result = await runTypegenGenerate({
133
+ config: typegenConfig,
134
+ onProgress: createTypegenProgressRenderer(spin, {
135
+ formatGeneratedCode: typegenConfig.formatGeneratedCode,
136
+ generates: typegenConfig.generates,
137
+ schema: typegenConfig.schema
138
+ }),
139
+ workDir
140
+ });
141
+ const traceStats = omit(result, 'code', 'duration');
142
+ trace.log({
143
+ configMethod: typegenConfigMethod,
144
+ configOverloadClientMethods: typegenConfig.overloadClientMethods,
145
+ ...traceStats
146
+ });
147
+ trace.complete();
148
+ } catch (error) {
149
+ if (spin?.isSpinning) {
150
+ spin.fail();
151
+ }
152
+ trace.error(error instanceof Error ? error : new Error(String(error)));
153
+ this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {
154
+ exit: 1
155
+ });
156
+ }
157
+ }
158
+ async runWatcher() {
159
+ const trace = this.telemetry.trace(TypegenWatchModeTrace);
160
+ let spin;
161
+ try {
162
+ const { config: typegenConfig, workDir } = await this.getConfig();
163
+ trace.start();
164
+ let resolve = ()=>{};
165
+ const promise = new Promise((res)=>{
166
+ resolve = res;
167
+ });
168
+ const watchSpin = spinner({}).start('Loading schema…');
169
+ spin = watchSpin;
170
+ const rendererContext = {
171
+ formatGeneratedCode: typegenConfig.formatGeneratedCode,
172
+ generates: typegenConfig.generates,
173
+ schema: typegenConfig.schema
174
+ };
175
+ let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext);
176
+ const typegenWatcher = runTypegenWatcher({
177
+ config: typegenConfig,
178
+ onProgress: (event)=>{
179
+ // 'schemaLoaded' is the first event of every generation cycle; the
180
+ // renderer accumulates per-run state, so start each cycle fresh.
181
+ if (event.type === 'schemaLoaded') {
182
+ renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext);
183
+ }
184
+ renderProgress(event);
185
+ },
186
+ workDir
187
+ });
188
+ const stop = once(async ()=>{
189
+ process.off('SIGINT', stop);
190
+ process.off('SIGTERM', stop);
191
+ if (watchSpin.isSpinning) {
192
+ watchSpin.stop();
193
+ }
194
+ trace.log({
195
+ step: 'stopped',
196
+ ...typegenWatcher.getStats()
197
+ });
198
+ trace.complete();
199
+ try {
200
+ await typegenWatcher.stop();
201
+ } catch {
202
+ // We're shutting down; a failure to close the watcher shouldn't hang
203
+ // the process or surface as an unhandled rejection.
204
+ }
205
+ resolve();
206
+ });
207
+ process.on('SIGINT', stop);
208
+ process.on('SIGTERM', stop);
209
+ await promise;
210
+ } catch (error) {
211
+ if (spin?.isSpinning) {
212
+ spin.fail();
213
+ }
214
+ trace.error(error instanceof Error ? error : new Error(String(error)));
215
+ this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {
216
+ exit: 1
217
+ });
218
+ }
219
+ }
220
+ }
221
+
222
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n configDefinition,\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.`.trim()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {exit: 1})\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: 1,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n return {\n config: configDefinition.parse(config.typegen || {}),\n path: rootDir.path,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: configDefinition.parse(config.typegen || {}),\n path: rootDir.path,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {exit: 1})\n }\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, type: typegenConfigMethod, workDir} = await this.getConfig()\n trace.start()\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {exit: 1})\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, workDir} = await this.getConfig()\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({}).start('Loading schema…')\n spin = watchSpin\n const rendererContext = {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }\n let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n\n const typegenWatcher = runTypegenWatcher({\n config: typegenConfig,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {exit: 1})\n }\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","SanityCommand","spinner","configDefinition","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","createTypegenProgressRenderer","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","typegen","warn","path","type","succeed","trace","telemetry","typegenConfig","typegenConfigMethod","result","onProgress","formatGeneratedCode","generates","schema","traceStats","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","isSpinning","String","message","resolve","promise","Promise","res","watchSpin","rendererContext","renderProgress","typegenWatcher","event","stop","process","off","step","getStats","on"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { Flags } from '@oclif/core';
3
3
  import { SanityCommand } from '@sanity/cli-core';
4
- import { Table } from 'console-table-printer';
5
4
  import sortBy from 'lodash-es/sortBy.js';
6
5
  import { getMembersForProject } from '../../actions/users/getMembersForProject.js';
7
6
  import { promptForProject } from '../../prompts/promptForProject.js';
7
+ import { Table } from '../../util/responsiveTable.js';
8
8
  import { getProjectIdFlag } from '../../util/sharedFlags.js';
9
9
  const sortFields = [
10
10
  'id',
@@ -105,35 +105,35 @@ export class List extends SanityCommand {
105
105
  ]), [
106
106
  sortFields.indexOf(sort)
107
107
  ]);
108
- const rows = order === 'asc' ? ordered : ordered.toReversed();
108
+ const rows = (order === 'asc' ? ordered : ordered.toReversed()).map(([id, name, roles, date])=>[
109
+ id,
110
+ name,
111
+ roles,
112
+ date.split('T')[0]
113
+ ]);
109
114
  const table = new Table({
110
115
  columns: [
111
116
  {
112
117
  alignment: 'left',
113
- maxLen: 30,
114
118
  name: 'id',
115
119
  title: 'ID'
116
120
  },
117
121
  {
118
122
  alignment: 'left',
119
- maxLen: 40,
120
123
  name: 'name',
121
124
  title: 'Name'
122
125
  },
123
126
  {
124
127
  alignment: 'left',
125
- maxLen: 30,
126
128
  name: 'roles',
127
129
  title: 'Roles'
128
130
  },
129
131
  {
130
132
  alignment: 'left',
131
- maxLen: 12,
132
133
  name: 'date',
133
134
  title: 'Date'
134
135
  }
135
- ],
136
- rowSeparator: true
136
+ ]
137
137
  });
138
138
  for (const [id, name, roles, date] of rows){
139
139
  const isPending = id === '<pending>';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/users/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {getMembersForProject} from '../../actions/users/getMembersForProject.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst sortFields = ['id', 'name', 'role', 'date']\n\nfunction dimText(value: string, isDim: boolean): string {\n return isDim ? styleText('dim', value) : value\n}\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List project members'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all users of the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-invitations --no-robots',\n description: 'List all users of the project, but exclude pending invitations and robots',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort role',\n description: 'List all users, sorted by role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List users for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list users for',\n semantics: 'override',\n }),\n invitations: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes pending invitations',\n }),\n order: Flags.string({\n default: 'asc',\n description: 'Sort output ascending/descending',\n options: ['asc', 'desc'],\n }),\n robots: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes robots (token users)',\n }),\n sort: Flags.string({\n default: 'date',\n description: 'Sort users by specified column',\n options: ['id', 'name', 'role', 'date'],\n }),\n }\n\n static override hiddenAliases: string[] = ['user:list']\n\n public async run(): Promise<void> {\n const {invitations, order, robots, sort} = this.flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project'},\n {grant: 'read', permission: 'sanity.project.members'},\n ],\n }),\n })\n\n const members = await getMembersForProject({\n includeInvitations: invitations,\n includeRobots: robots,\n projectId,\n })\n\n if (members.length === 0) {\n this.log('No members found for this project.')\n return\n }\n\n const ordered = sortBy(\n members.map(({date, id, name, roles}) => [\n id,\n name,\n roles\n ?.map((role) => role.title)\n .join(', ')\n .trim() || '-',\n date,\n ]),\n [sortFields.indexOf(sort)],\n )\n\n const rows = order === 'asc' ? ordered : ordered.toReversed()\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 30, name: 'id', title: 'ID'},\n {alignment: 'left', maxLen: 40, name: 'name', title: 'Name'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n {alignment: 'left', maxLen: 12, name: 'date', title: 'Date'},\n ],\n rowSeparator: true,\n })\n\n for (const [id, name, roles, date] of rows) {\n const isPending = id === '<pending>'\n table.addRow({\n date: dimText(date, isPending),\n id: dimText(id, isPending),\n name: dimText(name, isPending),\n roles: dimText(roles, isPending),\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["styleText","Flags","SanityCommand","Table","sortBy","getMembersForProject","promptForProject","getProjectIdFlag","sortFields","dimText","value","isDim","List","description","examples","command","flags","semantics","invitations","boolean","allowNo","default","order","string","options","robots","sort","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","members","includeInvitations","includeRobots","length","log","ordered","map","date","id","name","roles","role","title","join","trim","indexOf","rows","toReversed","table","columns","alignment","maxLen","rowSeparator","isPending","addRow","render"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/users/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {getMembersForProject} from '../../actions/users/getMembersForProject.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst sortFields = ['id', 'name', 'role', 'date']\n\nfunction dimText(value: string, isDim: boolean): string {\n return isDim ? styleText('dim', value) : value\n}\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List project members'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all users of the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-invitations --no-robots',\n description: 'List all users of the project, but exclude pending invitations and robots',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort role',\n description: 'List all users, sorted by role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List users for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list users for',\n semantics: 'override',\n }),\n invitations: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes pending invitations',\n }),\n order: Flags.string({\n default: 'asc',\n description: 'Sort output ascending/descending',\n options: ['asc', 'desc'],\n }),\n robots: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes robots (token users)',\n }),\n sort: Flags.string({\n default: 'date',\n description: 'Sort users by specified column',\n options: ['id', 'name', 'role', 'date'],\n }),\n }\n\n static override hiddenAliases: string[] = ['user:list']\n\n public async run(): Promise<void> {\n const {invitations, order, robots, sort} = this.flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project'},\n {grant: 'read', permission: 'sanity.project.members'},\n ],\n }),\n })\n\n const members = await getMembersForProject({\n includeInvitations: invitations,\n includeRobots: robots,\n projectId,\n })\n\n if (members.length === 0) {\n this.log('No members found for this project.')\n return\n }\n\n const ordered = sortBy(\n members.map(({date, id, name, roles}) => [\n id,\n name,\n roles\n ?.map((role) => role.title)\n .join(', ')\n .trim() || '-',\n date,\n ]),\n [sortFields.indexOf(sort)],\n )\n\n const rows = (order === 'asc' ? ordered : ordered.toReversed()).map(\n ([id, name, roles, date]) => [id, name, roles, date.split('T')[0]],\n )\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'name', title: 'Name'},\n {alignment: 'left', name: 'roles', title: 'Roles'},\n {alignment: 'left', name: 'date', title: 'Date'},\n ],\n })\n\n for (const [id, name, roles, date] of rows) {\n const isPending = id === '<pending>'\n table.addRow({\n date: dimText(date, isPending),\n id: dimText(id, isPending),\n name: dimText(name, isPending),\n roles: dimText(roles, isPending),\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["styleText","Flags","SanityCommand","sortBy","getMembersForProject","promptForProject","Table","getProjectIdFlag","sortFields","dimText","value","isDim","List","description","examples","command","flags","semantics","invitations","boolean","allowNo","default","order","string","options","robots","sort","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","members","includeInvitations","includeRobots","length","log","ordered","map","date","id","name","roles","role","title","join","trim","indexOf","rows","toReversed","split","table","columns","alignment","isPending","addRow","render"],"mappings":"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"}
@@ -1,7 +1,22 @@
1
1
  import { getStudioEnvironmentVariables } from "@sanity/cli-build/_internal/env";
2
+ import { Interfaces } from "@oclif/core";
2
3
  import { Schema } from "@sanity/types";
3
4
  import { StudioEnvVariablesOptions } from "@sanity/cli-build/_internal/env";
4
5
 
6
+ /** @internal */
7
+ export declare interface CommandTelemetry {
8
+ redactedFlags: readonly RedactedFlag[];
9
+ }
10
+
11
+ declare type CommandTelemetryConfig<Flags extends Interfaces.FlagInput> = {
12
+ redact?: readonly OptionFlagName<Flags>[];
13
+ };
14
+
15
+ /** @internal */
16
+ export declare function defineCommandTelemetry<
17
+ const Flags extends Interfaces.FlagInput,
18
+ >(flags: Flags, config: CommandTelemetryConfig<Flags>): CommandTelemetry;
19
+
5
20
  /**
6
21
  * Extracts all serializable properties from userland schema types,
7
22
  * so they best-effort can be used as definitions for Schema.compile.
@@ -85,6 +100,20 @@ declare type ManifestValidationRule = {
85
100
  flag: string;
86
101
  };
87
102
 
103
+ declare type OptionFlagName<Flags extends Interfaces.FlagInput> = string &
104
+ {
105
+ [Name in keyof Flags]: Flags[Name] extends {
106
+ type: "option";
107
+ }
108
+ ? Name
109
+ : never;
110
+ }[keyof Flags];
111
+
112
+ declare interface RedactedFlag {
113
+ canonical: string;
114
+ flags: readonly string[];
115
+ }
116
+
88
117
  export { StudioEnvVariablesOptions };
89
118
 
90
119
  export {};
@@ -1,4 +1,5 @@
1
1
  export { extractManifestSchemaTypes } from '../actions/manifest/extractWorkspaceManifest.js';
2
+ export { defineCommandTelemetry } from '../util/telemetry/commandTelemetry.js';
2
3
  export { getStudioEnvironmentVariables } from '@sanity/cli-build/_internal/env';
3
4
 
4
5
  //# sourceMappingURL=_internal.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/_internal.ts"],"sourcesContent":["export {extractManifestSchemaTypes} from '../actions/manifest/extractWorkspaceManifest.js'\nexport {\n getStudioEnvironmentVariables,\n type StudioEnvVariablesOptions,\n} from '@sanity/cli-build/_internal/env'\n"],"names":["extractManifestSchemaTypes","getStudioEnvironmentVariables"],"mappings":"AAAA,SAAQA,0BAA0B,QAAO,kDAAiD;AAC1F,SACEC,6BAA6B,QAExB,kCAAiC"}
1
+ {"version":3,"sources":["../../src/exports/_internal.ts"],"sourcesContent":["export {extractManifestSchemaTypes} from '../actions/manifest/extractWorkspaceManifest.js'\nexport {type CommandTelemetry, defineCommandTelemetry} from '../util/telemetry/commandTelemetry.js'\nexport {\n getStudioEnvironmentVariables,\n type StudioEnvVariablesOptions,\n} from '@sanity/cli-build/_internal/env'\n"],"names":["extractManifestSchemaTypes","defineCommandTelemetry","getStudioEnvironmentVariables"],"mappings":"AAAA,SAAQA,0BAA0B,QAAO,kDAAiD;AAC1F,SAA+BC,sBAAsB,QAAO,wCAAuC;AACnG,SACEC,6BAA6B,QAExB,kCAAiC"}
@@ -44,6 +44,8 @@ function apiValidator({ args, flags }) {
44
44
  ],
45
45
  validate: apiValidator
46
46
  }),
47
+ // Reads a file from the machine running the command and must only run locally.
48
+ 'assets:upload': deny,
47
49
  'backups:disable': allow,
48
50
  // Writes a downloaded backup to the local filesystem.
49
51
  'backups:download': deny,
@@ -175,6 +177,10 @@ function apiValidator({ args, flags }) {
175
177
  'tokens:delete': deny,
176
178
  // Exposes authentication credential metadata.
177
179
  'tokens:list': deny,
180
+ // Replaces authentication credentials and exposes the new secret.
181
+ 'tokens:rotate': deny,
182
+ // Reads the local schema and source files and writes generated types to the project.
183
+ 'typegen:generate': deny,
178
184
  // Loads local CLI and workbench configuration to identify the deployed Studio or application.
179
185
  undeploy: deny,
180
186
  // Grants a user access to a project.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from './policy.js'\n\nfunction apiValidator({\n args,\n flags,\n}: {\n args: Readonly<Record<string, unknown>>\n flags: Readonly<Record<string, unknown>>\n}): boolean {\n const fields: unknown[] = Array.isArray(flags.field) ? flags.field : []\n\n const fieldReadsFromHost = fields.some((field) => {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n })\n if (fieldReadsFromHost) return false\n\n const headers: unknown[] = Array.isArray(flags.header) ? flags.header : []\n\n const headerOverridesAuthentication = headers.some((header) => {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n if (separatorIndex <= 0) return false\n\n const name = header.slice(0, separatorIndex).trim().toLowerCase()\n return name === 'authorization' || name === 'cookie'\n })\n\n if (headerOverridesAuthentication) return false\n\n const endpoint = typeof args.endpoint === 'string' ? URL.parse(args.endpoint) : null\n const urlEmbedsCredentials =\n endpoint !== null && (endpoint.username !== '' || endpoint.password !== '')\n\n return !urlEmbedsCredentials\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every manifest command must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token`, Authorization, and Cookie headers replace the MCP user's authentication,\n // URL-embedded credentials replace it with Basic authentication,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: apiValidator,\n }),\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // Reads media assets from the local filesystem.\n 'media:import': deny,\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // Writes project setup values and scaffolds local applications.\n new: deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n // Reads locally stored claim URLs and robot tokens.\n 'projects:unclaimed': deny,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","apiValidator","args","flags","fields","Array","isArray","field","fieldReadsFromHost","some","separatorIndex","indexOf","headers","header","headerOverridesAuthentication","name","slice","trim","toLowerCase","endpoint","URL","parse","urlEmbedsCredentials","username","password","mcpPolicy","api","deniedFlags","validate","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","new","preview","undeploy","versions"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from './policy.js'\n\nfunction apiValidator({\n args,\n flags,\n}: {\n args: Readonly<Record<string, unknown>>\n flags: Readonly<Record<string, unknown>>\n}): boolean {\n const fields: unknown[] = Array.isArray(flags.field) ? flags.field : []\n\n const fieldReadsFromHost = fields.some((field) => {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n })\n if (fieldReadsFromHost) return false\n\n const headers: unknown[] = Array.isArray(flags.header) ? flags.header : []\n\n const headerOverridesAuthentication = headers.some((header) => {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n if (separatorIndex <= 0) return false\n\n const name = header.slice(0, separatorIndex).trim().toLowerCase()\n return name === 'authorization' || name === 'cookie'\n })\n\n if (headerOverridesAuthentication) return false\n\n const endpoint = typeof args.endpoint === 'string' ? URL.parse(args.endpoint) : null\n const urlEmbedsCredentials =\n endpoint !== null && (endpoint.username !== '' || endpoint.password !== '')\n\n return !urlEmbedsCredentials\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every manifest command must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token`, Authorization, and Cookie headers replace the MCP user's authentication,\n // URL-embedded credentials replace it with Basic authentication,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: apiValidator,\n }),\n\n // Reads a file from the machine running the command and must only run locally.\n 'assets:upload': deny,\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // Reads media assets from the local filesystem.\n 'media:import': deny,\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // Writes project setup values and scaffolds local applications.\n new: deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n // Reads locally stored claim URLs and robot tokens.\n 'projects:unclaimed': deny,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n // Replaces authentication credentials and exposes the new secret.\n 'tokens:rotate': deny,\n\n // Reads the local schema and source files and writes generated types to the project.\n 'typegen:generate': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","apiValidator","args","flags","fields","Array","isArray","field","fieldReadsFromHost","some","separatorIndex","indexOf","headers","header","headerOverridesAuthentication","name","slice","trim","toLowerCase","endpoint","URL","parse","urlEmbedsCredentials","username","password","mcpPolicy","api","deniedFlags","validate","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","new","preview","undeploy","versions"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Help } from '@oclif/core';
2
2
  import { getHelpFlagAdditions } from '@oclif/core/help';
3
+ import { resolveTopicAliasInArgv } from '../../topicAliases.js';
3
4
  import { isConditionalInvocationPolicy } from './commandPolicies/policy.js';
4
5
  /** Command ids a policy exposes: entries that are not denied. */ function visibleCommandIds(policySet) {
5
6
  return new Set(Object.entries(policySet).filter(([, policy])=>policy.kind !== 'deny').map(([id])=>id));
@@ -96,6 +97,9 @@ import { isConditionalInvocationPolicy } from './commandPolicies/policy.js';
96
97
  this.commandId = command.id;
97
98
  return super.showCommandHelp(withoutDeniedFlags(command, this.policySet[command.id]));
98
99
  }
100
+ async showHelp(argv) {
101
+ return super.showHelp(resolveTopicAliasInArgv(argv));
102
+ }
99
103
  async showTopicHelp(topic) {
100
104
  if (!this.topicNames.has(topic.name)) throw new NotInvokableError(topic.name);
101
105
  return super.showTopicHelp({