@sanity/cli 8.21.0 → 8.22.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 (74) hide show
  1. package/README.md +106 -47
  2. package/codemods/dashboard.js +111 -0
  3. package/dist/actions/build/buildApp.js +1 -1
  4. package/dist/actions/build/buildApp.js.map +1 -1
  5. package/dist/actions/build/buildStudio.js +1 -1
  6. package/dist/actions/build/buildStudio.js.map +1 -1
  7. package/dist/actions/codemods/dashboard.js +113 -0
  8. package/dist/actions/codemods/dashboard.js.map +1 -0
  9. package/dist/actions/codemods/index.js +2 -0
  10. package/dist/actions/codemods/index.js.map +1 -1
  11. package/dist/actions/codemods/types.js.map +1 -1
  12. package/dist/actions/deploy/deployApp.js +13 -6
  13. package/dist/actions/deploy/deployApp.js.map +1 -1
  14. package/dist/actions/deploy/deployChecks.js +12 -7
  15. package/dist/actions/deploy/deployChecks.js.map +1 -1
  16. package/dist/actions/deploy/deployRunner.js +14 -8
  17. package/dist/actions/deploy/deployRunner.js.map +1 -1
  18. package/dist/actions/deploy/deployStudio.js +39 -4
  19. package/dist/actions/deploy/deployStudio.js.map +1 -1
  20. package/dist/actions/deploy/resolveDeployTarget.js +7 -6
  21. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  22. package/dist/actions/init/project/promptForAppTemplateSetup.js +22 -0
  23. package/dist/actions/init/project/promptForAppTemplateSetup.js.map +1 -1
  24. package/dist/actions/schema/listSchemas.js +2 -3
  25. package/dist/actions/schema/listSchemas.js.map +1 -1
  26. package/dist/actions/typegen/generateResourceTypes.js +11 -8
  27. package/dist/actions/typegen/generateResourceTypes.js.map +1 -1
  28. package/dist/actions/typegen/watchResourceTypes.js +208 -0
  29. package/dist/actions/typegen/watchResourceTypes.js.map +1 -0
  30. package/dist/actions/undeploy/runUndeploy.js +14 -8
  31. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  32. package/dist/commands/codemod.js +15 -4
  33. package/dist/commands/codemod.js.map +1 -1
  34. package/dist/commands/context/get.js +3 -8
  35. package/dist/commands/context/get.js.map +1 -1
  36. package/dist/commands/context/imports/download.js +3 -8
  37. package/dist/commands/context/imports/download.js.map +1 -1
  38. package/dist/commands/context/imports/get.js +3 -8
  39. package/dist/commands/context/imports/get.js.map +1 -1
  40. package/dist/commands/context/imports/list.js +3 -8
  41. package/dist/commands/context/imports/list.js.map +1 -1
  42. package/dist/commands/context/jobs/get.js +8 -8
  43. package/dist/commands/context/jobs/get.js.map +1 -1
  44. package/dist/commands/context/list.js +2 -6
  45. package/dist/commands/context/list.js.map +1 -1
  46. package/dist/commands/deploy.js +1 -0
  47. package/dist/commands/deploy.js.map +1 -1
  48. package/dist/commands/doctor.js +2 -1
  49. package/dist/commands/doctor.js.map +1 -1
  50. package/dist/commands/openapi/list.js +2 -4
  51. package/dist/commands/openapi/list.js.map +1 -1
  52. package/dist/commands/projects/create.js +3 -6
  53. package/dist/commands/projects/create.js.map +1 -1
  54. package/dist/commands/schemas/list.js +1 -3
  55. package/dist/commands/schemas/list.js.map +1 -1
  56. package/dist/commands/tokens/create.js +2 -5
  57. package/dist/commands/tokens/create.js.map +1 -1
  58. package/dist/commands/tokens/list.js +2 -6
  59. package/dist/commands/tokens/list.js.map +1 -1
  60. package/dist/commands/tokens/rotate.js +2 -5
  61. package/dist/commands/tokens/rotate.js.map +1 -1
  62. package/dist/commands/typegen/generate.js +83 -45
  63. package/dist/commands/typegen/generate.js.map +1 -1
  64. package/dist/commands/undeploy.js +1 -0
  65. package/dist/commands/undeploy.js.map +1 -1
  66. package/dist/commands/whoami.js +5 -11
  67. package/dist/commands/whoami.js.map +1 -1
  68. package/dist/exports/invokeSanityCli/index.js +26 -6
  69. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  70. package/dist/generated/apiRoutes.js +11 -26
  71. package/dist/generated/apiRoutes.js.map +1 -1
  72. package/dist/telemetry/init.telemetry.js.map +1 -1
  73. package/oclif.manifest.json +1323 -1294
  74. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/projects/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {type DatasetResponse} from '@sanity/client'\n\nimport {createDataset} from '../../actions/dataset/create.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {getOrganization} from '../../actions/organizations/getOrganization.js'\nimport {getManageUrl} from '../../actions/projects/getManageUrl.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForDefaultConfig} from '../../prompts/promptForDefaultConfig.js'\nimport {promptForProjectName} from '../../prompts/promptForProjectName.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectFeatures} from '../../services/getProjectFeatures.js'\nimport {\n type OrganizationCreateResponse,\n type ProjectOrganization,\n} from '../../services/organizations.js'\nimport {createProject, type CreateProjectResult} from '../../services/projects.js'\nimport {getCliUser} from '../../services/user.js'\n\nconst debug = subdebug('projects:create')\n\nexport class CreateProjectCommand extends SanityCommand<typeof CreateProjectCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Name of the project to create',\n required: false,\n }),\n }\n\n static override description = 'Create a new Sanity project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project named \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Project\" --organization=my-org',\n description: 'Create a project in a specific organization',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"My Project\" --dataset=staging --dataset-visibility=private',\n description: 'Create a project with a private dataset named \"staging\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Project\" --yes --json',\n description: 'Create a project non-interactively with JSON output',\n },\n ]\n\n static override flags = {\n dataset: Flags.string({\n description: 'Create a dataset. Prompts for visibility unless specified or --yes used',\n parse: async (input) => {\n const datasetNameError = validateDatasetName(input)\n if (datasetNameError) {\n throw new CLIError(datasetNameError, {exit: exitCodes.USAGE_ERROR})\n }\n\n return input\n },\n }),\n 'dataset-visibility': Flags.string({\n description: 'Dataset visibility: public or private',\n options: ['private', 'public'],\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output in JSON format',\n }),\n organization: Flags.string({\n description: 'Organization to create the project in',\n helpValue: '<slug|id>',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Skip prompts and use defaults (project: \"My Sanity Project\", dataset: production, visibility: public)',\n }),\n }\n\n static override hiddenAliases: string[] = ['project:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateProjectCommand)\n const {projectName} = args\n const {dataset, 'dataset-visibility': datasetVisibility, organization, yes} = flags\n const user = await getCliUser()\n\n const finalProjectName =\n projectName ||\n (yes || this.isUnattended() ? 'My Sanity Project' : await promptForProjectName())\n\n debug('Creating project with options: %O', {\n dataset,\n datasetVisibility,\n organizationId: organization,\n projectName,\n unattended: yes,\n })\n\n let chosenOrganization: OrganizationCreateResponse | ProjectOrganization | undefined\n try {\n chosenOrganization = await getOrganization({\n isUnattended: this.isUnattended(),\n output: this.output,\n requestedId: organization,\n user,\n })\n } catch (error) {\n const errorText = organization\n ? `Failed to retrieve organization ${organization}`\n : 'Failed to retrieve an organization'\n return this.output.error(`${errorText}: ${error}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const spin = spinner('Creating project').start()\n let newProject\n try {\n newProject = await createProject({\n displayName: finalProjectName,\n metadata: {\n integration: 'cli',\n },\n organizationId: chosenOrganization?.id,\n })\n spin.succeed('Project created successfully')\n } catch (error) {\n spin.fail()\n debug(`Failed to create project: ${error}`)\n return this.output.error(`Failed to create project: ${error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n let newDataset: DatasetResponse | undefined\n // If dataset name specified, or in attended mode (to prompt for dataset name), create a dataset.\n if (dataset || !this.isUnattended()) {\n newDataset = await this.handleDatasetCreation(\n newProject.projectId,\n dataset,\n datasetVisibility,\n )\n }\n\n this.printProjectCreationSuccess(chosenOrganization, newProject, newDataset)\n }\n\n private async handleDatasetCreation(\n projectId: string,\n datasetFromFlag?: string,\n datasetVisibility?: string,\n ): Promise<DatasetResponse | undefined> {\n try {\n let datasetName: string | undefined = datasetFromFlag\n const existingDatasets = await listDatasets(projectId)\n const existingDatasetNames = existingDatasets.map((ds) => ds.name)\n\n // Prompt for dataset in interactive mode if not provided\n if (!datasetName && !this.isUnattended()) {\n const wantsDataset = await confirm({\n default: true,\n message: 'Would you like to create a dataset?',\n })\n\n if (wantsDataset) {\n const defaultConfig = await promptForDefaultConfig()\n\n datasetName = defaultConfig\n ? 'production'\n : await promptForDatasetName({}, existingDatasetNames)\n }\n }\n\n // Create dataset if we have a name\n if (datasetName) {\n const projectFeatures = await getProjectFeatures(projectId)\n return await createDataset({\n datasetName,\n isUnattended: this.isUnattended(),\n output: this.output,\n projectFeatures,\n projectId,\n silent: this.flags.json,\n visibility: datasetVisibility,\n })\n }\n\n return\n } catch (error) {\n debug(`Error creating dataset: ${error}`)\n this.output.warn(`Project created but dataset creation failed: ${error}`)\n return\n }\n }\n\n private async printProjectCreationSuccess(\n organization: OrganizationCreateResponse | ProjectOrganization | undefined,\n project: CreateProjectResult,\n dataset: DatasetResponse | undefined,\n ) {\n if (this.flags.json) {\n this.output.log(JSON.stringify(project, null, 2))\n return\n }\n\n this.output.log(`Project created successfully!`)\n this.output.log(`ID: ${project.projectId}`)\n this.output.log(`Name: ${project.displayName}`)\n this.output.log(`Organization: ${organization?.name || 'Personal'}`)\n\n if (dataset) {\n this.output.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`)\n }\n\n this.output.log(``)\n this.output.log(`Manage your project: ${getManageUrl(project.projectId)}`)\n }\n}\n"],"names":["Args","Flags","CLIError","exitCodes","subdebug","SanityCommand","confirm","spinner","createDataset","validateDatasetName","getOrganization","getManageUrl","promptForDatasetName","promptForDefaultConfig","promptForProjectName","listDatasets","getProjectFeatures","createProject","getCliUser","debug","CreateProjectCommand","args","projectName","string","description","required","examples","command","flags","dataset","parse","input","datasetNameError","exit","USAGE_ERROR","options","json","boolean","default","organization","helpValue","yes","char","hiddenAliases","run","datasetVisibility","user","finalProjectName","isUnattended","organizationId","unattended","chosenOrganization","output","requestedId","error","errorText","RUNTIME_ERROR","spin","start","newProject","displayName","metadata","integration","id","succeed","fail","newDataset","handleDatasetCreation","projectId","printProjectCreationSuccess","datasetFromFlag","datasetName","existingDatasets","existingDatasetNames","map","ds","name","wantsDataset","message","defaultConfig","projectFeatures","silent","visibility","warn","project","log","JSON","stringify","aclMode"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/projects/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {type DatasetResponse} from '@sanity/client'\n\nimport {createDataset} from '../../actions/dataset/create.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {getOrganization} from '../../actions/organizations/getOrganization.js'\nimport {getManageUrl} from '../../actions/projects/getManageUrl.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForDefaultConfig} from '../../prompts/promptForDefaultConfig.js'\nimport {promptForProjectName} from '../../prompts/promptForProjectName.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectFeatures} from '../../services/getProjectFeatures.js'\nimport {\n type OrganizationCreateResponse,\n type ProjectOrganization,\n} from '../../services/organizations.js'\nimport {createProject, type CreateProjectResult} from '../../services/projects.js'\nimport {getCliUser} from '../../services/user.js'\n\nconst debug = subdebug('projects:create')\n\nexport class CreateProjectCommand extends SanityCommand<typeof CreateProjectCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Name of the project to create',\n required: false,\n }),\n }\n\n static override description = 'Create a new Sanity project'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project named \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Project\" --organization=my-org',\n description: 'Create a project in a specific organization',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"My Project\" --dataset=staging --dataset-visibility=private',\n description: 'Create a project with a private dataset named \"staging\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Project\" --yes --json',\n description: 'Create a project non-interactively with JSON output',\n },\n ]\n\n static override flags = {\n dataset: Flags.string({\n description: 'Create a dataset. Prompts for visibility unless specified or --yes used',\n parse: async (input) => {\n const datasetNameError = validateDatasetName(input)\n if (datasetNameError) {\n throw new CLIError(datasetNameError, {exit: exitCodes.USAGE_ERROR})\n }\n\n return input\n },\n }),\n 'dataset-visibility': Flags.string({\n description: 'Dataset visibility: public or private',\n options: ['private', 'public'],\n }),\n organization: Flags.string({\n description: 'Organization to create the project in',\n helpValue: '<slug|id>',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Skip prompts and use defaults (project: \"My Sanity Project\", dataset: production, visibility: public)',\n }),\n }\n\n static override hiddenAliases: string[] = ['project:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateProjectCommand)\n const {projectName} = args\n const {dataset, 'dataset-visibility': datasetVisibility, organization, yes} = flags\n const user = await getCliUser()\n\n const finalProjectName =\n projectName ||\n (yes || this.isUnattended() ? 'My Sanity Project' : await promptForProjectName())\n\n debug('Creating project with options: %O', {\n dataset,\n datasetVisibility,\n organizationId: organization,\n projectName,\n unattended: yes,\n })\n\n let chosenOrganization: OrganizationCreateResponse | ProjectOrganization | undefined\n try {\n chosenOrganization = await getOrganization({\n isUnattended: this.isUnattended(),\n output: this.output,\n requestedId: organization,\n user,\n })\n } catch (error) {\n const errorText = organization\n ? `Failed to retrieve organization ${organization}`\n : 'Failed to retrieve an organization'\n return this.output.error(`${errorText}: ${error}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const spin = spinner('Creating project').start()\n let newProject\n try {\n newProject = await createProject({\n displayName: finalProjectName,\n metadata: {\n integration: 'cli',\n },\n organizationId: chosenOrganization?.id,\n })\n spin.succeed('Project created successfully')\n } catch (error) {\n spin.fail()\n debug(`Failed to create project: ${error}`)\n return this.output.error(`Failed to create project: ${error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n let newDataset: DatasetResponse | undefined\n // If dataset name specified, or in attended mode (to prompt for dataset name), create a dataset.\n if (dataset || !this.isUnattended()) {\n newDataset = await this.handleDatasetCreation(\n newProject.projectId,\n dataset,\n datasetVisibility,\n )\n }\n\n this.printProjectCreationSuccess(chosenOrganization, newProject, newDataset)\n }\n\n private async handleDatasetCreation(\n projectId: string,\n datasetFromFlag?: string,\n datasetVisibility?: string,\n ): Promise<DatasetResponse | undefined> {\n try {\n let datasetName: string | undefined = datasetFromFlag\n const existingDatasets = await listDatasets(projectId)\n const existingDatasetNames = existingDatasets.map((ds) => ds.name)\n\n // Prompt for dataset in interactive mode if not provided\n if (!datasetName && !this.isUnattended()) {\n const wantsDataset = await confirm({\n default: true,\n message: 'Would you like to create a dataset?',\n })\n\n if (wantsDataset) {\n const defaultConfig = await promptForDefaultConfig()\n\n datasetName = defaultConfig\n ? 'production'\n : await promptForDatasetName({}, existingDatasetNames)\n }\n }\n\n // Create dataset if we have a name\n if (datasetName) {\n const projectFeatures = await getProjectFeatures(projectId)\n return await createDataset({\n datasetName,\n isUnattended: this.isUnattended(),\n output: this.output,\n projectFeatures,\n projectId,\n silent: this.flags.json,\n visibility: datasetVisibility,\n })\n }\n\n return\n } catch (error) {\n debug(`Error creating dataset: ${error}`)\n this.output.logDiagnostic(`Warning: Project created but dataset creation failed: ${error}`)\n return\n }\n }\n\n private async printProjectCreationSuccess(\n organization: OrganizationCreateResponse | ProjectOrganization | undefined,\n project: CreateProjectResult,\n dataset: DatasetResponse | undefined,\n ) {\n if (this.flags.json) {\n this.logJson(project)\n return\n }\n\n this.output.log(`Project created successfully!`)\n this.output.log(`ID: ${project.projectId}`)\n this.output.log(`Name: ${project.displayName}`)\n this.output.log(`Organization: ${organization?.name || 'Personal'}`)\n\n if (dataset) {\n this.output.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`)\n }\n\n this.output.log(``)\n this.output.log(`Manage your project: ${getManageUrl(project.projectId)}`)\n }\n}\n"],"names":["Args","Flags","CLIError","exitCodes","subdebug","SanityCommand","confirm","spinner","createDataset","validateDatasetName","getOrganization","getManageUrl","promptForDatasetName","promptForDefaultConfig","promptForProjectName","listDatasets","getProjectFeatures","createProject","getCliUser","debug","CreateProjectCommand","args","projectName","string","description","required","enableJsonFlag","examples","command","flags","dataset","parse","input","datasetNameError","exit","USAGE_ERROR","options","organization","helpValue","yes","boolean","char","default","hiddenAliases","run","datasetVisibility","user","finalProjectName","isUnattended","organizationId","unattended","chosenOrganization","output","requestedId","error","errorText","RUNTIME_ERROR","spin","start","newProject","displayName","metadata","integration","id","succeed","fail","newDataset","handleDatasetCreation","projectId","printProjectCreationSuccess","datasetFromFlag","datasetName","existingDatasets","existingDatasetNames","map","ds","name","wantsDataset","message","defaultConfig","projectFeatures","silent","json","visibility","logDiagnostic","project","logJson","log","aclMode"],"mappings":"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"}
@@ -12,6 +12,7 @@ Regenerates a manifest file by default. To reuse an existing manifest, use --no-
12
12
  `.trim();
13
13
  export class ListSchemaCommand extends SanityCommand {
14
14
  static description = description;
15
+ static enableJsonFlag = true;
15
16
  static examples = [
16
17
  {
17
18
  command: '<%= config.bin %> <%= command.id %>',
@@ -41,9 +42,6 @@ export class ListSchemaCommand extends SanityCommand {
41
42
  description: 'Fetch a single schema by id',
42
43
  helpValue: '<schema_id>'
43
44
  }),
44
- json: Flags.boolean({
45
- description: 'Get schema as json'
46
- }),
47
45
  'manifest-dir': Flags.directory({
48
46
  default: './dist/static',
49
47
  description: 'Directory containing manifest file',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/schemas/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\n\nimport {listSchemas} from '../../actions/schema/listSchemas.js'\nimport {schemasListDebug} from '../../actions/schema/utils/debug.js'\nimport {parseWorkspaceSchemaId} from '../../actions/schema/utils/schemaStoreValidation.js'\n\nconst description = `\nList all schemas in the current dataset.\n\nNote: This command is experimental and subject to change.\n\nRegenerates a manifest file by default. To reuse an existing manifest, use --no-extract-manifest.\n`.trim()\n\nexport class ListSchemaCommand extends SanityCommand<typeof ListSchemaCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all schemas found in any workspace dataset in a table',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --id _.schemas.workspaceName',\n description: 'Get a schema for a given id',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Get stored schemas as pretty-printed json-array',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --id _.schemas.workspaceName',\n description: 'Get singular stored schema as pretty-printed json-object',\n },\n ]\n\n static override flags = {\n 'extract-manifest': Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Regenerate manifest before listing (use --no-extract-manifest to skip)',\n hidden: true,\n }),\n id: Flags.string({\n description: 'Fetch a single schema by id',\n helpValue: '<schema_id>',\n }),\n json: Flags.boolean({\n description: 'Get schema as json',\n }),\n 'manifest-dir': Flags.directory({\n default: './dist/static',\n description: 'Directory containing manifest file',\n helpValue: '<directory>',\n hidden: true,\n }),\n }\n\n static override hiddenAliases: string[] = ['schema:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(ListSchemaCommand)\n const errors: string[] = []\n const id = parseWorkspaceSchemaId(errors, flags.id)?.schemaId\n if (errors.length > 0) {\n this.error(`Invalid arguments:\\n${errors.map((error) => ` - ${error}`).join('\\n')}`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n try {\n const projectRoot = await this.getProjectRoot()\n\n await listSchemas({\n configPath: projectRoot.path,\n id,\n json: !!flags.json,\n output: this.output,\n workDir: projectRoot.directory,\n })\n } catch (error) {\n schemasListDebug('Failed to list schemas', error)\n\n const errorMessage = error instanceof Error ? error.message : String(error)\n this.error(`Failed to list schemas:\\n${errorMessage}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","listSchemas","schemasListDebug","parseWorkspaceSchemaId","description","trim","ListSchemaCommand","examples","command","flags","boolean","allowNo","default","hidden","id","string","helpValue","json","directory","hiddenAliases","run","parse","errors","schemaId","length","error","map","join","exit","USAGE_ERROR","projectRoot","getProjectRoot","configPath","path","output","workDir","errorMessage","Error","message","String","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzD,SAAQC,WAAW,QAAO,sCAAqC;AAC/D,SAAQC,gBAAgB,QAAO,sCAAqC;AACpE,SAAQC,sBAAsB,QAAO,sDAAqD;AAE1F,MAAMC,cAAc,CAAC;;;;;;AAMrB,CAAC,CAACC,IAAI;AAEN,OAAO,MAAMC,0BAA0BN;IACrC,OAAgBI,cAAcA,YAAW;IAEzC,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,oBAAoBX,MAAMY,OAAO,CAAC;YAChCC,SAAS;YACTC,SAAS;YACTR,aAAa;YACbS,QAAQ;QACV;QACAC,IAAIhB,MAAMiB,MAAM,CAAC;YACfX,aAAa;YACbY,WAAW;QACb;QACAC,MAAMnB,MAAMY,OAAO,CAAC;YAClBN,aAAa;QACf;QACA,gBAAgBN,MAAMoB,SAAS,CAAC;YAC9BN,SAAS;YACTR,aAAa;YACbY,WAAW;YACXH,QAAQ;QACV;IACF,EAAC;IAED,OAAgBM,gBAA0B;QAAC;KAAc,CAAA;IAEzD,MAAaC,MAAqB;QAChC,MAAM,EAACX,KAAK,EAAC,GAAG,MAAM,IAAI,CAACY,KAAK,CAACf;QACjC,MAAMgB,SAAmB,EAAE;QAC3B,MAAMR,KAAKX,uBAAuBmB,QAAQb,MAAMK,EAAE,GAAGS;QACrD,IAAID,OAAOE,MAAM,GAAG,GAAG;YACrB,IAAI,CAACC,KAAK,CAAC,CAAC,oBAAoB,EAAEH,OAAOI,GAAG,CAAC,CAACD,QAAU,CAAC,IAAI,EAAEA,OAAO,EAAEE,IAAI,CAAC,OAAO,EAAE;gBACpFC,MAAM7B,UAAU8B,WAAW;YAC7B;QACF;QAEA,IAAI;YACF,MAAMC,cAAc,MAAM,IAAI,CAACC,cAAc;YAE7C,MAAM9B,YAAY;gBAChB+B,YAAYF,YAAYG,IAAI;gBAC5BnB;gBACAG,MAAM,CAAC,CAACR,MAAMQ,IAAI;gBAClBiB,QAAQ,IAAI,CAACA,MAAM;gBACnBC,SAASL,YAAYZ,SAAS;YAChC;QACF,EAAE,OAAOO,OAAO;YACdvB,iBAAiB,0BAA0BuB;YAE3C,MAAMW,eAAeX,iBAAiBY,QAAQZ,MAAMa,OAAO,GAAGC,OAAOd;YACrE,IAAI,CAACA,KAAK,CAAC,CAAC,yBAAyB,EAAEW,cAAc,EAAE;gBAACR,MAAM7B,UAAUyC,aAAa;YAAA;QACvF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/schemas/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\n\nimport {listSchemas} from '../../actions/schema/listSchemas.js'\nimport {schemasListDebug} from '../../actions/schema/utils/debug.js'\nimport {parseWorkspaceSchemaId} from '../../actions/schema/utils/schemaStoreValidation.js'\n\nconst description = `\nList all schemas in the current dataset.\n\nNote: This command is experimental and subject to change.\n\nRegenerates a manifest file by default. To reuse an existing manifest, use --no-extract-manifest.\n`.trim()\n\nexport class ListSchemaCommand extends SanityCommand<typeof ListSchemaCommand> {\n static override description = description\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all schemas found in any workspace dataset in a table',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --id _.schemas.workspaceName',\n description: 'Get a schema for a given id',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Get stored schemas as pretty-printed json-array',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --id _.schemas.workspaceName',\n description: 'Get singular stored schema as pretty-printed json-object',\n },\n ]\n\n static override flags = {\n 'extract-manifest': Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Regenerate manifest before listing (use --no-extract-manifest to skip)',\n hidden: true,\n }),\n id: Flags.string({\n description: 'Fetch a single schema by id',\n helpValue: '<schema_id>',\n }),\n 'manifest-dir': Flags.directory({\n default: './dist/static',\n description: 'Directory containing manifest file',\n helpValue: '<directory>',\n hidden: true,\n }),\n }\n\n static override hiddenAliases: string[] = ['schema:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(ListSchemaCommand)\n const errors: string[] = []\n const id = parseWorkspaceSchemaId(errors, flags.id)?.schemaId\n if (errors.length > 0) {\n this.error(`Invalid arguments:\\n${errors.map((error) => ` - ${error}`).join('\\n')}`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n try {\n const projectRoot = await this.getProjectRoot()\n\n await listSchemas({\n configPath: projectRoot.path,\n id,\n json: !!flags.json,\n output: this.output,\n workDir: projectRoot.directory,\n })\n } catch (error) {\n schemasListDebug('Failed to list schemas', error)\n\n const errorMessage = error instanceof Error ? error.message : String(error)\n this.error(`Failed to list schemas:\\n${errorMessage}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","listSchemas","schemasListDebug","parseWorkspaceSchemaId","description","trim","ListSchemaCommand","enableJsonFlag","examples","command","flags","boolean","allowNo","default","hidden","id","string","helpValue","directory","hiddenAliases","run","parse","errors","schemaId","length","error","map","join","exit","USAGE_ERROR","projectRoot","getProjectRoot","configPath","path","json","output","workDir","errorMessage","Error","message","String","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzD,SAAQC,WAAW,QAAO,sCAAqC;AAC/D,SAAQC,gBAAgB,QAAO,sCAAqC;AACpE,SAAQC,sBAAsB,QAAO,sDAAqD;AAE1F,MAAMC,cAAc,CAAC;;;;;;AAMrB,CAAC,CAACC,IAAI;AAEN,OAAO,MAAMC,0BAA0BN;IACrC,OAAgBI,cAAcA,YAAW;IAEzC,OAAgBG,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTL,aAAa;QACf;QACA;YACEK,SAAS;YACTL,aAAa;QACf;QACA;YACEK,SAAS;YACTL,aAAa;QACf;QACA;YACEK,SAAS;YACTL,aAAa;QACf;KACD,CAAA;IAED,OAAgBM,QAAQ;QACtB,oBAAoBZ,MAAMa,OAAO,CAAC;YAChCC,SAAS;YACTC,SAAS;YACTT,aAAa;YACbU,QAAQ;QACV;QACAC,IAAIjB,MAAMkB,MAAM,CAAC;YACfZ,aAAa;YACba,WAAW;QACb;QACA,gBAAgBnB,MAAMoB,SAAS,CAAC;YAC9BL,SAAS;YACTT,aAAa;YACba,WAAW;YACXH,QAAQ;QACV;IACF,EAAC;IAED,OAAgBK,gBAA0B;QAAC;KAAc,CAAA;IAEzD,MAAaC,MAAqB;QAChC,MAAM,EAACV,KAAK,EAAC,GAAG,MAAM,IAAI,CAACW,KAAK,CAACf;QACjC,MAAMgB,SAAmB,EAAE;QAC3B,MAAMP,KAAKZ,uBAAuBmB,QAAQZ,MAAMK,EAAE,GAAGQ;QACrD,IAAID,OAAOE,MAAM,GAAG,GAAG;YACrB,IAAI,CAACC,KAAK,CAAC,CAAC,oBAAoB,EAAEH,OAAOI,GAAG,CAAC,CAACD,QAAU,CAAC,IAAI,EAAEA,OAAO,EAAEE,IAAI,CAAC,OAAO,EAAE;gBACpFC,MAAM7B,UAAU8B,WAAW;YAC7B;QACF;QAEA,IAAI;YACF,MAAMC,cAAc,MAAM,IAAI,CAACC,cAAc;YAE7C,MAAM9B,YAAY;gBAChB+B,YAAYF,YAAYG,IAAI;gBAC5BlB;gBACAmB,MAAM,CAAC,CAACxB,MAAMwB,IAAI;gBAClBC,QAAQ,IAAI,CAACA,MAAM;gBACnBC,SAASN,YAAYZ,SAAS;YAChC;QACF,EAAE,OAAOO,OAAO;YACdvB,iBAAiB,0BAA0BuB;YAE3C,MAAMY,eAAeZ,iBAAiBa,QAAQb,MAAMc,OAAO,GAAGC,OAAOf;YACrE,IAAI,CAACA,KAAK,CAAC,CAAC,yBAAyB,EAAEY,cAAc,EAAE;gBAACT,MAAM7B,UAAU0C,aAAa;YAAA;QACvF;IACF;AACF"}
@@ -29,6 +29,7 @@ export class CreateTokenCommand extends SanityCommand {
29
29
  })
30
30
  };
31
31
  static description = 'Create a new API token with access to an organization and its projects';
32
+ static enableJsonFlag = true;
32
33
  static examples = [
33
34
  {
34
35
  command: '<%= config.bin %> <%= command.id %> "My API Token"',
@@ -73,10 +74,6 @@ export class CreateTokenCommand extends SanityCommand {
73
74
  helpValue: 'context=editor',
74
75
  multiple: true
75
76
  }),
76
- json: Flags.boolean({
77
- default: false,
78
- description: 'Output as JSON'
79
- }),
80
77
  role: Flags.string({
81
78
  description: 'Role to assign on the project (defaults to viewer in unattended mode)',
82
79
  helpValue: 'viewer'
@@ -130,7 +127,7 @@ export class CreateTokenCommand extends SanityCommand {
130
127
  });
131
128
  }
132
129
  if (flags.json) {
133
- this.log(JSON.stringify(token, null, 2));
130
+ this.logJson(token);
134
131
  return;
135
132
  }
136
133
  this.log('API token created');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/tokens/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, isProjectRootNotFoundError} from '@sanity/cli-core/errors'\nimport {input, select} from '@sanity/cli-core/ux'\nimport {ClientError} from '@sanity/client'\n\nimport {\n MissingOrganizationError,\n resolveOrganizationId,\n} from '../../actions/context/resolveOrganizationId.js'\nimport {expiryInDays, parseExpiryDate} from '../../actions/tokens/expiry.js'\nimport {\n DEFAULT_ROLE,\n findGrantConflict,\n formatGrant,\n getProjectTokenMembership,\n type Grant,\n parseGrant,\n projectGrantKey,\n toMemberships,\n} from '../../actions/tokens/grants.js'\nimport {type RobotWithToken} from '../../actions/tokens/types.js'\nimport {validateRole} from '../../actions/tokens/validateRole.js'\nimport {promptForGrants} from '../../prompts/promptForGrants.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listProjects} from '../../services/projects.js'\nimport {createOrganizationToken, createToken} from '../../services/tokens.js'\nimport {getOrganizationFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst tokensCreateDebug = subdebug('tokens:create')\n\ntype Access = {\n expiresAt: string | undefined\n grants: Grant[]\n\n organizationId?: string\n roleTitle?: string\n}\n\n// Mirrors the expiry presets offered by sanity.io/manage\nconst EXPIRY_PRESET_DAYS = [30, 60, 90]\n\nconst ORGANIZATION_FORBIDDEN_MESSAGE =\n 'You need permission to create organization tokens. Grant a single project to create a project token instead.'\n\nexport class CreateTokenCommand extends SanityCommand<typeof CreateTokenCommand> {\n static override args = {\n label: Args.string({\n description: 'Label for the new token',\n required: false,\n }),\n }\n\n static override description =\n 'Create a new API token with access to an organization and its projects'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> \"My API Token\"',\n description: 'Create a token, choosing its access interactively',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"CI Token\" --grant context=developer --grant blueprints --grant project:abc123=editor',\n description: 'Create an organization token with Context, Blueprints and project access',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Token\" --project-id abc123 --role=editor',\n description: 'Create a project token with editor role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Token\" --role=editor --yes',\n description: 'Create a project token in unattended mode',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"Build Token\" --expires-at 2027-01-01',\n description: 'Create a token that expires on a given date',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"API Token\" --json',\n description: 'Output token information as JSON',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to create token in',\n semantics: 'override',\n }),\n ...getOrganizationFlag({\n description: 'Organization to create an organization token in',\n semantics: 'override',\n }),\n 'expires-at': Flags.string({\n description: 'Date or timestamp the token expires (ISO 8601; tokens never expire by default)',\n helpValue: '2027-01-01',\n }),\n grant: Flags.string({\n description:\n 'Access to grant, as <permission>[=<role>] or project:<projectId>=<role>[,<role>]. Permissions: context, blueprints, media-library, canvas, sdk-apps, access, deploy-studios. Repeatable',\n helpValue: 'context=editor',\n multiple: true,\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output as JSON',\n }),\n role: Flags.string({\n description: 'Role to assign on the project (defaults to viewer in unattended mode)',\n helpValue: 'viewer',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skip prompts and use defaults (unattended mode)',\n }),\n }\n\n static override hiddenAliases: string[] = ['tokens:add', 'token:add', 'token:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateTokenCommand)\n const {label: givenLabel} = args\n\n const label = givenLabel === undefined ? await this.promptForLabel() : givenLabel.trim()\n if (!label) {\n this.error('Token label cannot be empty. Pass a non-empty value as the `<label>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const flagExpiresAt = this.parseExpiryFlag(flags['expires-at'])\n const getExpiry = async () =>\n flags['expires-at'] === undefined ? this.promptForExpiry() : flagExpiresAt\n const flagGrants = (flags.grant ?? []).map((value) => this.parseGrantFlag(value))\n const grantConflict = findGrantConflict(flagGrants)\n if (grantConflict) {\n this.error(grantConflict, {exit: exitCodes.USAGE_ERROR})\n }\n\n const {expiresAt, grants, organizationId, roleTitle}: Access =\n this.isUnattended() || flagGrants.length > 0 || flags.role !== undefined\n ? {...(await this.getFlagGrants(flagGrants)), expiresAt: await getExpiry()}\n : await this.promptForAccess(getExpiry)\n\n let token: RobotWithToken\n try {\n token = await this.createTokenForGrants({\n expiresAt,\n grants,\n label,\n organizationId,\n })\n } catch (error) {\n if (error instanceof CLIError) throw error\n tokensCreateDebug('Error creating token', error)\n this.error(`Token creation failed:\\n${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (flags.json) {\n this.log(JSON.stringify(token, null, 2))\n return\n }\n\n this.log('API token created')\n this.log(`Label: ${token.label}`)\n this.log(`ID: ${token.id}`)\n if (roleTitle) {\n this.log(`Role: ${roleTitle}`)\n }\n if (token.expiresAt) {\n this.log(`Expires: ${token.expiresAt}`)\n }\n this.log(`Token: ${token.token}`)\n this.log('')\n this.log(\"Copy the token now. It won't be shown again.\")\n\n if (!this.isUnattended()) {\n this.log('')\n this.log('To create the same token without prompts:')\n this.log(` ${formatCreateCommand(this.config.bin, {expiresAt, grants, label, token})}`)\n }\n }\n\n private async createTokenForGrants(options: {\n expiresAt: string | undefined\n grants: Grant[]\n label: string\n organizationId: string | undefined\n }): Promise<RobotWithToken> {\n const {expiresAt, grants, label} = options\n const projectMembership = getProjectTokenMembership(grants)\n if (projectMembership) {\n const {resourceId: projectId, roleNames} = projectMembership\n return createToken({expiresAt, label, projectId, roleNames})\n }\n\n const organizationId = options.organizationId ?? (await this.resolveOrganization())\n try {\n return await createOrganizationToken({\n expiresAt,\n label,\n memberships: toMemberships(grants, organizationId),\n organizationId,\n })\n } catch (error) {\n if (error instanceof ClientError && error.statusCode === 403) {\n throw new Error(ORGANIZATION_FORBIDDEN_MESSAGE, {cause: error})\n }\n throw error\n }\n }\n\n private async getFlagGrants(grants: Grant[]): Promise<{grants: Grant[]; roleTitle?: string}> {\n const {'project-id': projectIdFlag, role} = this.flags\n if (grants.length > 0 && !projectIdFlag && !role) {\n return {grants}\n }\n\n const projectId = await this.resolveProjectId()\n const projectKey = projectGrantKey(projectId)\n if (grants.some((grant) => grant.key === projectKey)) {\n if (role) {\n this.error(\n `Set the role for project ${projectId} with either --role or --grant ${projectKey}=<role>, not both.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n return {grants}\n }\n\n const projectRole = role ? await validateRole(role, projectId, this.output) : DEFAULT_ROLE\n\n return {\n grants: [...grants, {key: projectKey, roles: [projectRole.name]}],\n roleTitle: grants.length === 0 ? projectRole.title : undefined,\n }\n }\n\n private parseExpiryFlag(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined\n }\n\n const parsed = parseExpiryDate(value)\n if ('error' in parsed) {\n this.error(parsed.error, {exit: exitCodes.USAGE_ERROR})\n }\n\n return parsed.expiresAt\n }\n\n private parseGrantFlag(value: string): Grant {\n const parsed = parseGrant(value.trim())\n if ('error' in parsed) {\n this.error(parsed.error, {exit: exitCodes.USAGE_ERROR})\n }\n\n return parsed.grant\n }\n\n private async promptForAccess(getExpiry: () => Promise<string | undefined>): Promise<Access> {\n const requestedProjectId = this.flags['project-id']\n const configProjectId = (await this.tryGetCliConfig()).api?.projectId\n const projects = await listProjects({onlyExplicitMembership: false})\n const organizationOf = (projectId: string | undefined) =>\n projects.find((project) => project.id === projectId)?.organizationId ?? undefined\n const organizationId = await this.resolveOrganization({\n fallback: organizationOf(configProjectId),\n preferred: organizationOf(requestedProjectId),\n })\n const organizationProjects = projects.filter(\n (project) => project.organizationId === organizationId,\n )\n if (requestedProjectId && !organizationProjects.some(({id}) => id === requestedProjectId)) {\n this.error(\n `Project ${requestedProjectId} isn't in organization ${organizationId}, or you don't have access to it.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const expiresAt = await getExpiry()\n const grants = await promptForGrants({\n preselectedProjectId: requestedProjectId,\n projects: organizationProjects,\n })\n return {expiresAt, grants, organizationId}\n }\n\n private async promptForExpiry(): Promise<string | undefined> {\n if (this.isUnattended()) {\n return undefined // Tokens never expire by default\n }\n\n const choice = await select({\n choices: [\n {name: 'Never', value: 'never'},\n ...EXPIRY_PRESET_DAYS.map((days) => ({\n name: `${days} days (${expiryInDays(days).slice(0, 10)})`,\n value: String(days),\n })),\n {name: 'Custom date', value: 'custom'},\n ],\n default: 'never',\n message: 'Token expiry:',\n })\n\n if (choice === 'never') {\n return undefined\n }\n\n if (choice === 'custom') {\n const value = await input({\n message: 'Expiry date (ISO 8601, e.g. 2027-01-01):',\n validate: (input) => {\n const parsed = parseExpiryDate(input.trim())\n return 'error' in parsed ? parsed.error : true\n },\n })\n const parsed = parseExpiryDate(value.trim())\n return 'error' in parsed ? undefined : parsed.expiresAt\n }\n\n return expiryInDays(Number(choice))\n }\n\n private async promptForLabel(): Promise<string> {\n if (this.isUnattended()) {\n this.error('Token label is required. Pass it as the `<label>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const label = await input({\n message: 'Token label:',\n validate: (value) => {\n if (!value || !value.trim()) {\n return 'Label cannot be empty'\n }\n return true\n },\n })\n\n return label.trim()\n }\n\n private async resolveOrganization(\n projectOrganizations: {fallback?: string; preferred?: string} = {},\n ): Promise<string> {\n const {fallback, preferred} = projectOrganizations\n try {\n return await resolveOrganizationId({\n configuredOrganizationId:\n preferred ?? (await this.tryGetCliConfig()).app?.organizationId ?? fallback,\n flagOrganizationId: this.flags.organization,\n unattended: this.isUnattended(),\n })\n } catch (error) {\n tokensCreateDebug('Error resolving organization', error)\n this.error(getErrorMessage(error), {\n exit:\n error instanceof MissingOrganizationError\n ? exitCodes.USAGE_ERROR\n : exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async resolveProjectId(): Promise<string> {\n if (!this.isUnattended()) {\n return this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.roles'},\n {grant: 'create', permission: 'sanity.project.tokens'},\n ],\n }),\n })\n }\n\n try {\n return await this.getProjectId()\n } catch (error) {\n if (!isProjectRootNotFoundError(error)) throw error\n this.error(\n 'Token access is required. Pass at least one `--grant`, or `--project-id` to create a project token.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n }\n}\n\nfunction quoteShellArg(value: string): string {\n return /^[\\w./:@=,-]+$/.test(value) ? value : `'${value.replaceAll(\"'\", String.raw`'\\''`)}'`\n}\n\nfunction formatCreateCommand(\n bin: string,\n {\n expiresAt,\n grants,\n label,\n token,\n }: {\n expiresAt: string | undefined\n grants: Grant[]\n label: string\n token: RobotWithToken\n },\n): string {\n const organizationId =\n token.managedBy?.resourceType === 'organization' ? token.managedBy.resourceId : undefined\n return [\n `${bin} tokens create`,\n quoteShellArg(label),\n ...(organizationId ? [`--organization ${organizationId}`] : []),\n ...(expiresAt ? [`--expires-at ${expiresAt}`] : []),\n ...grants.map((grant) => `--grant ${formatGrant(grant)}`),\n '--yes',\n ].join(' ')\n}\n"],"names":["Args","Flags","CLIError","exitCodes","SanityCommand","subdebug","getErrorMessage","isProjectRootNotFoundError","input","select","ClientError","MissingOrganizationError","resolveOrganizationId","expiryInDays","parseExpiryDate","DEFAULT_ROLE","findGrantConflict","formatGrant","getProjectTokenMembership","parseGrant","projectGrantKey","toMemberships","validateRole","promptForGrants","promptForProject","listProjects","createOrganizationToken","createToken","getOrganizationFlag","getProjectIdFlag","tokensCreateDebug","EXPIRY_PRESET_DAYS","ORGANIZATION_FORBIDDEN_MESSAGE","CreateTokenCommand","args","label","string","description","required","examples","command","flags","semantics","helpValue","grant","multiple","json","boolean","default","role","yes","char","hiddenAliases","run","parse","givenLabel","undefined","promptForLabel","trim","error","exit","USAGE_ERROR","flagExpiresAt","parseExpiryFlag","getExpiry","promptForExpiry","flagGrants","map","value","parseGrantFlag","grantConflict","expiresAt","grants","organizationId","roleTitle","isUnattended","length","getFlagGrants","promptForAccess","token","createTokenForGrants","RUNTIME_ERROR","log","JSON","stringify","id","formatCreateCommand","config","bin","options","projectMembership","resourceId","projectId","roleNames","resolveOrganization","memberships","statusCode","Error","cause","projectIdFlag","resolveProjectId","projectKey","some","key","projectRole","output","roles","name","title","parsed","requestedProjectId","configProjectId","tryGetCliConfig","api","projects","onlyExplicitMembership","organizationOf","find","project","fallback","preferred","organizationProjects","filter","preselectedProjectId","choice","choices","days","slice","String","message","validate","Number","projectOrganizations","configuredOrganizationId","app","flagOrganizationId","organization","unattended","getProjectId","requiredPermissions","permission","quoteShellArg","test","replaceAll","raw","managedBy","resourceType","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/tokens/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, isProjectRootNotFoundError} from '@sanity/cli-core/errors'\nimport {input, select} from '@sanity/cli-core/ux'\nimport {ClientError} from '@sanity/client'\n\nimport {\n MissingOrganizationError,\n resolveOrganizationId,\n} from '../../actions/context/resolveOrganizationId.js'\nimport {expiryInDays, parseExpiryDate} from '../../actions/tokens/expiry.js'\nimport {\n DEFAULT_ROLE,\n findGrantConflict,\n formatGrant,\n getProjectTokenMembership,\n type Grant,\n parseGrant,\n projectGrantKey,\n toMemberships,\n} from '../../actions/tokens/grants.js'\nimport {type RobotWithToken} from '../../actions/tokens/types.js'\nimport {validateRole} from '../../actions/tokens/validateRole.js'\nimport {promptForGrants} from '../../prompts/promptForGrants.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listProjects} from '../../services/projects.js'\nimport {createOrganizationToken, createToken} from '../../services/tokens.js'\nimport {getOrganizationFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst tokensCreateDebug = subdebug('tokens:create')\n\ntype Access = {\n expiresAt: string | undefined\n grants: Grant[]\n\n organizationId?: string\n roleTitle?: string\n}\n\n// Mirrors the expiry presets offered by sanity.io/manage\nconst EXPIRY_PRESET_DAYS = [30, 60, 90]\n\nconst ORGANIZATION_FORBIDDEN_MESSAGE =\n 'You need permission to create organization tokens. Grant a single project to create a project token instead.'\n\nexport class CreateTokenCommand extends SanityCommand<typeof CreateTokenCommand> {\n static override args = {\n label: Args.string({\n description: 'Label for the new token',\n required: false,\n }),\n }\n\n static override description =\n 'Create a new API token with access to an organization and its projects'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> \"My API Token\"',\n description: 'Create a token, choosing its access interactively',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"CI Token\" --grant context=developer --grant blueprints --grant project:abc123=editor',\n description: 'Create an organization token with Context, Blueprints and project access',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Token\" --project-id abc123 --role=editor',\n description: 'Create a project token with editor role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Token\" --role=editor --yes',\n description: 'Create a project token in unattended mode',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"Build Token\" --expires-at 2027-01-01',\n description: 'Create a token that expires on a given date',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"API Token\" --json',\n description: 'Output token information as JSON',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to create token in',\n semantics: 'override',\n }),\n ...getOrganizationFlag({\n description: 'Organization to create an organization token in',\n semantics: 'override',\n }),\n 'expires-at': Flags.string({\n description: 'Date or timestamp the token expires (ISO 8601; tokens never expire by default)',\n helpValue: '2027-01-01',\n }),\n grant: Flags.string({\n description:\n 'Access to grant, as <permission>[=<role>] or project:<projectId>=<role>[,<role>]. Permissions: context, blueprints, media-library, canvas, sdk-apps, access, deploy-studios. Repeatable',\n helpValue: 'context=editor',\n multiple: true,\n }),\n role: Flags.string({\n description: 'Role to assign on the project (defaults to viewer in unattended mode)',\n helpValue: 'viewer',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skip prompts and use defaults (unattended mode)',\n }),\n }\n\n static override hiddenAliases: string[] = ['tokens:add', 'token:add', 'token:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateTokenCommand)\n const {label: givenLabel} = args\n\n const label = givenLabel === undefined ? await this.promptForLabel() : givenLabel.trim()\n if (!label) {\n this.error('Token label cannot be empty. Pass a non-empty value as the `<label>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const flagExpiresAt = this.parseExpiryFlag(flags['expires-at'])\n const getExpiry = async () =>\n flags['expires-at'] === undefined ? this.promptForExpiry() : flagExpiresAt\n const flagGrants = (flags.grant ?? []).map((value) => this.parseGrantFlag(value))\n const grantConflict = findGrantConflict(flagGrants)\n if (grantConflict) {\n this.error(grantConflict, {exit: exitCodes.USAGE_ERROR})\n }\n\n const {expiresAt, grants, organizationId, roleTitle}: Access =\n this.isUnattended() || flagGrants.length > 0 || flags.role !== undefined\n ? {...(await this.getFlagGrants(flagGrants)), expiresAt: await getExpiry()}\n : await this.promptForAccess(getExpiry)\n\n let token: RobotWithToken\n try {\n token = await this.createTokenForGrants({\n expiresAt,\n grants,\n label,\n organizationId,\n })\n } catch (error) {\n if (error instanceof CLIError) throw error\n tokensCreateDebug('Error creating token', error)\n this.error(`Token creation failed:\\n${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (flags.json) {\n this.logJson(token)\n return\n }\n\n this.log('API token created')\n this.log(`Label: ${token.label}`)\n this.log(`ID: ${token.id}`)\n if (roleTitle) {\n this.log(`Role: ${roleTitle}`)\n }\n if (token.expiresAt) {\n this.log(`Expires: ${token.expiresAt}`)\n }\n this.log(`Token: ${token.token}`)\n this.log('')\n this.log(\"Copy the token now. It won't be shown again.\")\n\n if (!this.isUnattended()) {\n this.log('')\n this.log('To create the same token without prompts:')\n this.log(` ${formatCreateCommand(this.config.bin, {expiresAt, grants, label, token})}`)\n }\n }\n\n private async createTokenForGrants(options: {\n expiresAt: string | undefined\n grants: Grant[]\n label: string\n organizationId: string | undefined\n }): Promise<RobotWithToken> {\n const {expiresAt, grants, label} = options\n const projectMembership = getProjectTokenMembership(grants)\n if (projectMembership) {\n const {resourceId: projectId, roleNames} = projectMembership\n return createToken({expiresAt, label, projectId, roleNames})\n }\n\n const organizationId = options.organizationId ?? (await this.resolveOrganization())\n try {\n return await createOrganizationToken({\n expiresAt,\n label,\n memberships: toMemberships(grants, organizationId),\n organizationId,\n })\n } catch (error) {\n if (error instanceof ClientError && error.statusCode === 403) {\n throw new Error(ORGANIZATION_FORBIDDEN_MESSAGE, {cause: error})\n }\n throw error\n }\n }\n\n private async getFlagGrants(grants: Grant[]): Promise<{grants: Grant[]; roleTitle?: string}> {\n const {'project-id': projectIdFlag, role} = this.flags\n if (grants.length > 0 && !projectIdFlag && !role) {\n return {grants}\n }\n\n const projectId = await this.resolveProjectId()\n const projectKey = projectGrantKey(projectId)\n if (grants.some((grant) => grant.key === projectKey)) {\n if (role) {\n this.error(\n `Set the role for project ${projectId} with either --role or --grant ${projectKey}=<role>, not both.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n return {grants}\n }\n\n const projectRole = role ? await validateRole(role, projectId, this.output) : DEFAULT_ROLE\n\n return {\n grants: [...grants, {key: projectKey, roles: [projectRole.name]}],\n roleTitle: grants.length === 0 ? projectRole.title : undefined,\n }\n }\n\n private parseExpiryFlag(value: string | undefined): string | undefined {\n if (value === undefined) {\n return undefined\n }\n\n const parsed = parseExpiryDate(value)\n if ('error' in parsed) {\n this.error(parsed.error, {exit: exitCodes.USAGE_ERROR})\n }\n\n return parsed.expiresAt\n }\n\n private parseGrantFlag(value: string): Grant {\n const parsed = parseGrant(value.trim())\n if ('error' in parsed) {\n this.error(parsed.error, {exit: exitCodes.USAGE_ERROR})\n }\n\n return parsed.grant\n }\n\n private async promptForAccess(getExpiry: () => Promise<string | undefined>): Promise<Access> {\n const requestedProjectId = this.flags['project-id']\n const configProjectId = (await this.tryGetCliConfig()).api?.projectId\n const projects = await listProjects({onlyExplicitMembership: false})\n const organizationOf = (projectId: string | undefined) =>\n projects.find((project) => project.id === projectId)?.organizationId ?? undefined\n const organizationId = await this.resolveOrganization({\n fallback: organizationOf(configProjectId),\n preferred: organizationOf(requestedProjectId),\n })\n const organizationProjects = projects.filter(\n (project) => project.organizationId === organizationId,\n )\n if (requestedProjectId && !organizationProjects.some(({id}) => id === requestedProjectId)) {\n this.error(\n `Project ${requestedProjectId} isn't in organization ${organizationId}, or you don't have access to it.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const expiresAt = await getExpiry()\n const grants = await promptForGrants({\n preselectedProjectId: requestedProjectId,\n projects: organizationProjects,\n })\n return {expiresAt, grants, organizationId}\n }\n\n private async promptForExpiry(): Promise<string | undefined> {\n if (this.isUnattended()) {\n return undefined // Tokens never expire by default\n }\n\n const choice = await select({\n choices: [\n {name: 'Never', value: 'never'},\n ...EXPIRY_PRESET_DAYS.map((days) => ({\n name: `${days} days (${expiryInDays(days).slice(0, 10)})`,\n value: String(days),\n })),\n {name: 'Custom date', value: 'custom'},\n ],\n default: 'never',\n message: 'Token expiry:',\n })\n\n if (choice === 'never') {\n return undefined\n }\n\n if (choice === 'custom') {\n const value = await input({\n message: 'Expiry date (ISO 8601, e.g. 2027-01-01):',\n validate: (input) => {\n const parsed = parseExpiryDate(input.trim())\n return 'error' in parsed ? parsed.error : true\n },\n })\n const parsed = parseExpiryDate(value.trim())\n return 'error' in parsed ? undefined : parsed.expiresAt\n }\n\n return expiryInDays(Number(choice))\n }\n\n private async promptForLabel(): Promise<string> {\n if (this.isUnattended()) {\n this.error('Token label is required. Pass it as the `<label>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const label = await input({\n message: 'Token label:',\n validate: (value) => {\n if (!value || !value.trim()) {\n return 'Label cannot be empty'\n }\n return true\n },\n })\n\n return label.trim()\n }\n\n private async resolveOrganization(\n projectOrganizations: {fallback?: string; preferred?: string} = {},\n ): Promise<string> {\n const {fallback, preferred} = projectOrganizations\n try {\n return await resolveOrganizationId({\n configuredOrganizationId:\n preferred ?? (await this.tryGetCliConfig()).app?.organizationId ?? fallback,\n flagOrganizationId: this.flags.organization,\n unattended: this.isUnattended(),\n })\n } catch (error) {\n tokensCreateDebug('Error resolving organization', error)\n this.error(getErrorMessage(error), {\n exit:\n error instanceof MissingOrganizationError\n ? exitCodes.USAGE_ERROR\n : exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async resolveProjectId(): Promise<string> {\n if (!this.isUnattended()) {\n return this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.roles'},\n {grant: 'create', permission: 'sanity.project.tokens'},\n ],\n }),\n })\n }\n\n try {\n return await this.getProjectId()\n } catch (error) {\n if (!isProjectRootNotFoundError(error)) throw error\n this.error(\n 'Token access is required. Pass at least one `--grant`, or `--project-id` to create a project token.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n }\n}\n\nfunction quoteShellArg(value: string): string {\n return /^[\\w./:@=,-]+$/.test(value) ? value : `'${value.replaceAll(\"'\", String.raw`'\\''`)}'`\n}\n\nfunction formatCreateCommand(\n bin: string,\n {\n expiresAt,\n grants,\n label,\n token,\n }: {\n expiresAt: string | undefined\n grants: Grant[]\n label: string\n token: RobotWithToken\n },\n): string {\n const organizationId =\n token.managedBy?.resourceType === 'organization' ? token.managedBy.resourceId : undefined\n return [\n `${bin} tokens create`,\n quoteShellArg(label),\n ...(organizationId ? [`--organization ${organizationId}`] : []),\n ...(expiresAt ? [`--expires-at ${expiresAt}`] : []),\n ...grants.map((grant) => `--grant ${formatGrant(grant)}`),\n '--yes',\n ].join(' ')\n}\n"],"names":["Args","Flags","CLIError","exitCodes","SanityCommand","subdebug","getErrorMessage","isProjectRootNotFoundError","input","select","ClientError","MissingOrganizationError","resolveOrganizationId","expiryInDays","parseExpiryDate","DEFAULT_ROLE","findGrantConflict","formatGrant","getProjectTokenMembership","parseGrant","projectGrantKey","toMemberships","validateRole","promptForGrants","promptForProject","listProjects","createOrganizationToken","createToken","getOrganizationFlag","getProjectIdFlag","tokensCreateDebug","EXPIRY_PRESET_DAYS","ORGANIZATION_FORBIDDEN_MESSAGE","CreateTokenCommand","args","label","string","description","required","enableJsonFlag","examples","command","flags","semantics","helpValue","grant","multiple","role","yes","boolean","char","default","hiddenAliases","run","parse","givenLabel","undefined","promptForLabel","trim","error","exit","USAGE_ERROR","flagExpiresAt","parseExpiryFlag","getExpiry","promptForExpiry","flagGrants","map","value","parseGrantFlag","grantConflict","expiresAt","grants","organizationId","roleTitle","isUnattended","length","getFlagGrants","promptForAccess","token","createTokenForGrants","RUNTIME_ERROR","json","logJson","log","id","formatCreateCommand","config","bin","options","projectMembership","resourceId","projectId","roleNames","resolveOrganization","memberships","statusCode","Error","cause","projectIdFlag","resolveProjectId","projectKey","some","key","projectRole","output","roles","name","title","parsed","requestedProjectId","configProjectId","tryGetCliConfig","api","projects","onlyExplicitMembership","organizationOf","find","project","fallback","preferred","organizationProjects","filter","preselectedProjectId","choice","choices","days","slice","String","message","validate","Number","projectOrganizations","configuredOrganizationId","app","flagOrganizationId","organization","unattended","getProjectId","requiredPermissions","permission","quoteShellArg","test","replaceAll","raw","managedBy","resourceType","join"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { Flags } from '@oclif/core';
2
1
  import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
2
  import { getErrorMessage } from '@sanity/cli-core/errors';
4
3
  import { formatTokenAccess } from '../../actions/tokens/formatTokenAccess.js';
@@ -9,6 +8,7 @@ import { getOrganizationFlag, getProjectIdFlag } from '../../util/sharedFlags.js
9
8
  const listTokenDebug = subdebug('tokens:list');
10
9
  export class TokensListCommand extends SanityCommand {
11
10
  static description = 'List API tokens for a project or organization';
11
+ static enableJsonFlag = true;
12
12
  static examples = [
13
13
  {
14
14
  command: '<%= config.bin %> <%= command.id %> --organization org123',
@@ -38,10 +38,6 @@ export class TokensListCommand extends SanityCommand {
38
38
  ...getProjectIdFlag({
39
39
  description: 'Project ID to list tokens for',
40
40
  semantics: 'override'
41
- }),
42
- json: Flags.boolean({
43
- default: false,
44
- description: 'Output tokens in JSON format'
45
41
  })
46
42
  };
47
43
  static hiddenAliases = [
@@ -67,7 +63,7 @@ export class TokensListCommand extends SanityCommand {
67
63
  });
68
64
  }
69
65
  if (outputJson) {
70
- this.log(JSON.stringify(tokens, null, 2));
66
+ this.logJson(tokens);
71
67
  return;
72
68
  }
73
69
  if (tokens.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/tokens/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\n\nimport {formatTokenAccess} from '../../actions/tokens/formatTokenAccess.js'\nimport {type Robot} from '../../actions/tokens/types.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {resolveTokenScope} from '../../util/resolveTokenScope.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getOrganizationFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for a project or organization'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --organization org123',\n description: 'List tokens managed by an organization',\n },\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getOrganizationFlag({\n description: 'List tokens managed by this organization',\n exclusive: ['project-id'],\n semantics: 'specify',\n }),\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output tokens in JSON format',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n const scope = await resolveTokenScope({\n getProjectId: this.getProjectId.bind(this),\n grant: 'read',\n organization: flags.organization,\n })\n\n let tokens: Robot[]\n try {\n tokens = await getTokens(scope)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for ${scope.resourceType} ${scope.resourceId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (outputJson) {\n this.log(JSON.stringify(tokens, null, 2))\n return\n }\n\n if (tokens.length === 0) {\n this.log(`No API tokens found for this ${scope.resourceType}.`)\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'label', title: 'Label'},\n {alignment: 'left', name: 'id', title: 'ID'},\n {\n alignment: 'left',\n name: 'roles',\n title: scope.resourceType === 'organization' ? 'Access' : 'Roles',\n },\n {alignment: 'left', name: 'expires', title: 'Expires'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = formatTokenAccess(token, scope)\n\n table.addRow({\n expires: token.expiresAt ? token.expiresAt.slice(0, 10) : 'Never',\n id: token.id,\n label: token.label,\n roles,\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","formatTokenAccess","getTokens","resolveTokenScope","Table","getOrganizationFlag","getProjectIdFlag","listTokenDebug","TokensListCommand","description","examples","command","flags","exclusive","semantics","json","boolean","default","hiddenAliases","run","parse","outputJson","scope","getProjectId","bind","grant","organization","tokens","error","message","resourceType","resourceId","exit","RUNTIME_ERROR","log","JSON","stringify","length","table","columns","alignment","name","title","token","roles","addRow","expires","expiresAt","slice","id","label","render"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/tokens/list.ts"],"sourcesContent":["import {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\n\nimport {formatTokenAccess} from '../../actions/tokens/formatTokenAccess.js'\nimport {type Robot} from '../../actions/tokens/types.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {resolveTokenScope} from '../../util/resolveTokenScope.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getOrganizationFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for a project or organization'\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --organization org123',\n description: 'List tokens managed by an organization',\n },\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getOrganizationFlag({\n description: 'List tokens managed by this organization',\n exclusive: ['project-id'],\n semantics: 'specify',\n }),\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n const scope = await resolveTokenScope({\n getProjectId: this.getProjectId.bind(this),\n grant: 'read',\n organization: flags.organization,\n })\n\n let tokens: Robot[]\n try {\n tokens = await getTokens(scope)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for ${scope.resourceType} ${scope.resourceId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (outputJson) {\n this.logJson(tokens)\n return\n }\n\n if (tokens.length === 0) {\n this.log(`No API tokens found for this ${scope.resourceType}.`)\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'label', title: 'Label'},\n {alignment: 'left', name: 'id', title: 'ID'},\n {\n alignment: 'left',\n name: 'roles',\n title: scope.resourceType === 'organization' ? 'Access' : 'Roles',\n },\n {alignment: 'left', name: 'expires', title: 'Expires'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = formatTokenAccess(token, scope)\n\n table.addRow({\n expires: token.expiresAt ? token.expiresAt.slice(0, 10) : 'Never',\n id: token.id,\n label: token.label,\n roles,\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["exitCodes","SanityCommand","subdebug","getErrorMessage","formatTokenAccess","getTokens","resolveTokenScope","Table","getOrganizationFlag","getProjectIdFlag","listTokenDebug","TokensListCommand","description","enableJsonFlag","examples","command","flags","exclusive","semantics","hiddenAliases","run","parse","json","outputJson","scope","getProjectId","bind","grant","organization","tokens","error","message","resourceType","resourceId","exit","RUNTIME_ERROR","logJson","length","log","table","columns","alignment","name","title","token","roles","addRow","expires","expiresAt","slice","id","label","render"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AAEvD,SAAQC,iBAAiB,QAAO,4CAA2C;AAE3E,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,iBAAiB,QAAO,kCAAiC;AACjE,SAAQC,KAAK,QAAO,gCAA+B;AACnD,SAAQC,mBAAmB,EAAEC,gBAAgB,QAAO,4BAA2B;AAE/E,MAAMC,iBAAiBR,SAAS;AAEhC,OAAO,MAAMS,0BAA0BV;IACrC,OAAgBW,cAAc,gDAA+C;IAC7E,OAAgBC,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IACD,OAAgBI,QAAQ;QACtB,GAAGR,oBAAoB;YACrBI,aAAa;YACbK,WAAW;gBAAC;aAAa;YACzBC,WAAW;QACb,EAAE;QACF,GAAGT,iBAAiB;YAClBG,aAAa;YACbM,WAAW;QACb,EAAE;IACJ,EAAC;IAED,OAAgBC,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACJ,KAAK,EAAC,GAAG,MAAM,IAAI,CAACK,KAAK,CAACV;QACjC,MAAM,EAACW,IAAI,EAAC,GAAGN;QACf,MAAMO,aAAaD,QAAQ;QAE3B,MAAME,QAAQ,MAAMlB,kBAAkB;YACpCmB,cAAc,IAAI,CAACA,YAAY,CAACC,IAAI,CAAC,IAAI;YACzCC,OAAO;YACPC,cAAcZ,MAAMY,YAAY;QAClC;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMxB,UAAUmB;QAC3B,EAAE,OAAOM,OAAO;YACd,MAAMC,UAAU5B,gBAAgB2B;YAChCpB,eAAe,CAAC,0BAA0B,EAAEc,MAAMQ,YAAY,CAAC,CAAC,EAAER,MAAMS,UAAU,EAAE,EAAEH;YACtF,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACG,MAAMlC,UAAUmC,aAAa;YAAA;QACvF;QAEA,IAAIZ,YAAY;YACd,IAAI,CAACa,OAAO,CAACP;YACb;QACF;QAEA,IAAIA,OAAOQ,MAAM,KAAK,GAAG;YACvB,IAAI,CAACC,GAAG,CAAC,CAAC,6BAA6B,EAAEd,MAAMQ,YAAY,CAAC,CAAC,CAAC;YAC9D;QACF;QAEA,MAAMO,QAAQ,IAAIhC,MAAM;YACtBiC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAI;gBAC3C;oBACEF,WAAW;oBACXC,MAAM;oBACNC,OAAOnB,MAAMQ,YAAY,KAAK,iBAAiB,WAAW;gBAC5D;gBACA;oBAACS,WAAW;oBAAQC,MAAM;oBAAWC,OAAO;gBAAS;aACtD;YACDA,OAAO,CAAC,MAAM,EAAEd,OAAOQ,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMO,SAASf,OAAQ;YAC1B,MAAMgB,QAAQzC,kBAAkBwC,OAAOpB;YAEvCe,MAAMO,MAAM,CAAC;gBACXC,SAASH,MAAMI,SAAS,GAAGJ,MAAMI,SAAS,CAACC,KAAK,CAAC,GAAG,MAAM;gBAC1DC,IAAIN,MAAMM,EAAE;gBACZC,OAAOP,MAAMO,KAAK;gBAClBN;YACF;QACF;QAEA,IAAI,CAACP,GAAG,CAACC,MAAMa,MAAM;IACvB;AACF"}
@@ -8,6 +8,7 @@ const tokensRotateDebug = subdebug('tokens:rotate');
8
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
9
  export class RotateTokenCommand extends SanityCommand {
10
10
  static description = 'Rotate an API token, replacing its secret with a new one';
11
+ static enableJsonFlag = true;
11
12
  static examples = [
12
13
  {
13
14
  command: 'echo "$SANITY_TOKEN" | <%= config.bin %> <%= command.id %>',
@@ -23,10 +24,6 @@ export class RotateTokenCommand extends SanityCommand {
23
24
  }
24
25
  ];
25
26
  static flags = {
26
- json: Flags.boolean({
27
- default: false,
28
- description: 'Output as JSON'
29
- }),
30
27
  token: Flags.string({
31
28
  char: 't',
32
29
  description: 'Token to rotate (prefer standard input to keep it out of shell history)',
@@ -44,7 +41,7 @@ export class RotateTokenCommand extends SanityCommand {
44
41
  tokensRotateDebug('Rotating API token');
45
42
  const robot = await rotateToken(token);
46
43
  if (json) {
47
- this.log(JSON.stringify(robot, null, 2));
44
+ this.logJson(robot);
48
45
  return;
49
46
  }
50
47
  this.log('API token rotated');
@@ -1 +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"}
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 enableJsonFlag = true\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 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.logJson(robot)\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","enableJsonFlag","examples","command","flags","token","string","char","helpValue","hiddenAliases","run","parse","json","trim","readTokenArg","robot","logJson","log","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,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtBC,OAAOhB,MAAMiB,MAAM,CAAC;YAClBC,MAAM;YACNP,aAAa;YACbQ,WAAW;QACb;IACF,EAAC;IAED,OAAgBC,gBAA0B;QAAC;KAAe,CAAA;IAE1D,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACZ;QACjC,MAAM,EAACa,IAAI,EAAC,GAAGR;QAEf,MAAMC,QAAQD,MAAMC,KAAK,EAAEQ,UAAW,MAAM,IAAI,CAACC,YAAY;QAE7D,IAAI;YACFjB,kBAAkB;YAClB,MAAMkB,QAAQ,MAAMpB,YAAYU;YAEhC,IAAIO,MAAM;gBACR,IAAI,CAACI,OAAO,CAACD;gBACb;YACF;YAEA,IAAI,CAACE,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC,CAAC,OAAO,EAAEF,MAAMG,KAAK,EAAE;YAChC,IAAI,CAACD,GAAG,CAAC,CAAC,IAAI,EAAEF,MAAMI,EAAE,EAAE;YAC1B,IAAIJ,MAAMK,SAAS,EAAE;gBACnB,IAAI,CAACH,GAAG,CAAC,CAAC,SAAS,EAAEF,MAAMK,SAAS,EAAE;YACxC;YACA,IAAI,CAACH,GAAG,CAAC,CAAC,OAAO,EAAEF,MAAMV,KAAK,EAAE;YAChC,IAAI,CAACY,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC;YACT,IAAI,CAACA,GAAG,CAAC;QACX,EAAE,OAAOI,OAAO;YACdxB,kBAAkB,wBAAwBwB;YAE1C,IAAI3B,YAAY2B,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CACR,+GACA;oBAACE,MAAMjC,UAAUkC,aAAa;gBAAA;YAElC;YACA,IAAI9B,YAAY2B,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CACR,yGACA;oBAACE,MAAMjC,UAAUkC,aAAa;gBAAA;YAElC;YAEA,IAAI,CAACH,KAAK,CAAC,CAAC,wBAAwB,EAAE5B,gBAAgB4B,QAAQ,EAAE;gBAC9DE,MAAMjC,UAAUkC,aAAa;YAC/B;QACF;IACF;IAEA,MAAcV,eAAgC;QAC5C,IAAIT;QACJ,IAAI;YACFA,QAAQ,MAAMT,mBAAmBE;QACnC,EAAE,OAAOuB,OAAO;YACd,OAAO,IAAI,CAACA,KAAK,CAAC5B,gBAAgB4B,QAAQ;gBAACE,MAAMjC,UAAUmC,WAAW;YAAA;QACxE;QAEA,IAAI,CAACpB,OAAO;YACV,IAAI,CAACgB,KAAK,CAACvB,kBAAkB;gBAACyB,MAAMjC,UAAUmC,WAAW;YAAA;QAC3D;QAEA,OAAOpB;IACT;AACF"}
@@ -12,6 +12,7 @@ import { generateResourceTypes, resolveResourceSchemas } from '../../actions/typ
12
12
  import { parseTypegenConfig } from '../../actions/typegen/parseTypegenConfig.js';
13
13
  import { parseTypegenResources } from '../../actions/typegen/parseTypegenResources.js';
14
14
  import { createTypegenProgressRenderer } from '../../actions/typegen/renderTypegenProgress.js';
15
+ import { watchResourceTypes } from '../../actions/typegen/watchResourceTypes.js';
15
16
  const description = `Sanity TypeGen
16
17
 
17
18
  ${styleText('bold', 'Configuration:')}
@@ -30,7 +31,7 @@ The default configuration values listed above are used if not overridden in your
30
31
 
31
32
  ${styleText('bold', 'Note:')}
32
33
  - 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.
33
- - To generate types for several datasets, list them in \`typegen.resources\` in \`sanity.cli.ts\` (beta). Each resource uses its own \`schema\` file, or the schema bound to its dataset when \`schema\` is omitted.`.trim();
34
+ - To generate types for several datasets, list them in \`typegen.resources\` in \`sanity.cli.ts\` (beta). Each resource uses its own \`schema\` file, or the schema bound to its dataset when \`schema\` is omitted. With \`--watch\`, a schema bound to a dataset is fetched once, when the watcher starts. Restart it after deploying a schema.`.trim();
34
35
  export class TypegenGenerateCommand extends SanityCommand {
35
36
  static description = description;
36
37
  static examples = [
@@ -131,6 +132,25 @@ export class TypegenGenerateCommand extends SanityCommand {
131
132
  });
132
133
  }
133
134
  }
135
+ /**
136
+ * Prints the resources' configuration warnings, then locates every resource's schema, reporting
137
+ * each one on the spinner.
138
+ */ async resolveResources(resources, spin, workDir, { checkSchemaFiles }) {
139
+ for (const warning of resources.warnings){
140
+ this.output.warn(warning);
141
+ }
142
+ return resolveResourceSchemas({
143
+ checkSchemaFiles,
144
+ onResolved: (entry)=>{
145
+ spin.succeed('schemaPath' in entry ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}` : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`);
146
+ },
147
+ onResolving: (resource, key)=>{
148
+ spin.start(resource.schema === undefined ? `Fetching the schema bound to ${key}…` : `Checking the schema file for ${key}…`);
149
+ },
150
+ resources: resources.resources,
151
+ workDir
152
+ });
153
+ }
134
154
  async runSingle() {
135
155
  const trace = this.telemetry.trace(TypesGeneratedTrace);
136
156
  let spin;
@@ -138,31 +158,14 @@ export class TypegenGenerateCommand extends SanityCommand {
138
158
  const { config: typegenConfig, resources, type: typegenConfigMethod, workDir } = await this.getConfig();
139
159
  trace.start();
140
160
  if (resources) {
141
- for (const warning of resources.warnings){
142
- this.output.warn(warning);
143
- }
144
161
  const resourceSpin = spinner({});
145
162
  spin = resourceSpin;
146
- const resolved = await resolveResourceSchemas({
147
- onResolved: (entry)=>{
148
- resourceSpin.succeed('schemaPath' in entry ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}` : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`);
149
- },
150
- onResolving: (resource, key)=>{
151
- resourceSpin.start(resource.schema === undefined ? `Fetching the schema bound to ${key}…` : `Checking the schema file for ${key}…`);
152
- },
153
- resources: resources.resources,
154
- workDir
163
+ const resolved = await this.resolveResources(resources, resourceSpin, workDir, {
164
+ checkSchemaFiles: true
155
165
  });
156
166
  const results = await generateResourceTypes({
157
167
  config: typegenConfig,
158
- onProgress: (entry)=>{
159
- resourceSpin.start(`Generating types for ${entry.key}…`);
160
- return createTypegenProgressRenderer(resourceSpin, {
161
- formatGeneratedCode: typegenConfig.formatGeneratedCode,
162
- generates: entry.resource.generates,
163
- schema: 'schemaPath' in entry ? entry.schemaPath : entry.key
164
- });
165
- },
168
+ onProgress: createResourceProgressHandler(resourceSpin, typegenConfig),
166
169
  resolved,
167
170
  workDir
168
171
  });
@@ -208,36 +211,14 @@ export class TypegenGenerateCommand extends SanityCommand {
208
211
  let spin;
209
212
  try {
210
213
  const { config: typegenConfig, resources, workDir } = await this.getConfig();
211
- if (resources) {
212
- this.error('Watch mode does not support typegen.resources yet. Run "sanity typegen generate" without --watch.', {
213
- exit: exitCodes.USAGE_ERROR
214
- });
215
- }
216
214
  trace.start();
217
215
  let resolve = ()=>{};
218
216
  const promise = new Promise((res)=>{
219
217
  resolve = res;
220
218
  });
221
- const watchSpin = spinner({}).start('Loading schema…');
219
+ const watchSpin = spinner({});
222
220
  spin = watchSpin;
223
- const rendererContext = {
224
- formatGeneratedCode: typegenConfig.formatGeneratedCode,
225
- generates: typegenConfig.generates,
226
- schema: typegenConfig.schema
227
- };
228
- let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext);
229
- const typegenWatcher = runTypegenWatcher({
230
- config: typegenConfig,
231
- onProgress: (event)=>{
232
- // 'schemaLoaded' is the first event of every generation cycle; the
233
- // renderer accumulates per-run state, so start each cycle fresh.
234
- if (event.type === 'schemaLoaded') {
235
- renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext);
236
- }
237
- renderProgress(event);
238
- },
239
- workDir
240
- });
221
+ const typegenWatcher = resources ? await this.startResourceWatcher(typegenConfig, resources, watchSpin, workDir) : this.startSchemaWatcher(typegenConfig, watchSpin, workDir);
241
222
  const stop = once(async ()=>{
242
223
  process.off('SIGINT', stop);
243
224
  process.off('SIGTERM', stop);
@@ -272,6 +253,63 @@ export class TypegenGenerateCommand extends SanityCommand {
272
253
  });
273
254
  }
274
255
  }
256
+ /**
257
+ * Locates every resource's schema once, then generates on each query or local schema change.
258
+ * A schema bound to a dataset is fetched only here, so a schema deployed while the watcher runs
259
+ * is used after a restart.
260
+ */ async startResourceWatcher(config, resources, spin, workDir) {
261
+ // A missing local schema file fails that resource's generation until the file appears,
262
+ // instead of ending the watcher.
263
+ const resolved = await this.resolveResources(resources, spin, workDir, {
264
+ checkSchemaFiles: false
265
+ });
266
+ return watchResourceTypes({
267
+ config,
268
+ onChange: (event, relativePath)=>{
269
+ this.output.log(`[${new Date().toLocaleTimeString()}] ${event}: ${relativePath}`);
270
+ },
271
+ onError: (error)=>{
272
+ spin.fail(error instanceof Error ? error.message : String(error));
273
+ },
274
+ onProgress: createResourceProgressHandler(spin, config),
275
+ resolved,
276
+ workDir
277
+ });
278
+ }
279
+ startSchemaWatcher(config, spin, workDir) {
280
+ spin.start('Loading schema…');
281
+ const rendererContext = {
282
+ formatGeneratedCode: config.formatGeneratedCode,
283
+ generates: config.generates,
284
+ schema: config.schema
285
+ };
286
+ let renderProgress = createTypegenProgressRenderer(spin, rendererContext);
287
+ return runTypegenWatcher({
288
+ config,
289
+ onProgress: (event)=>{
290
+ // 'schemaLoaded' is the first event of every generation cycle; the
291
+ // renderer accumulates per-run state, so start each cycle fresh.
292
+ if (event.type === 'schemaLoaded') {
293
+ renderProgress = createTypegenProgressRenderer(spin, rendererContext);
294
+ }
295
+ renderProgress(event);
296
+ },
297
+ workDir
298
+ });
299
+ }
300
+ }
301
+ /**
302
+ * Returns the progress handler for one resource's generation, which starts with a line naming
303
+ * the resource. The renderer keeps per-run state, so each generation gets a new one.
304
+ */ function createResourceProgressHandler(spin, config) {
305
+ return (entry)=>{
306
+ spin.start(`Generating types for ${entry.key}…`);
307
+ return createTypegenProgressRenderer(spin, {
308
+ formatGeneratedCode: config.formatGeneratedCode,
309
+ generates: entry.resource.generates,
310
+ schema: 'schemaPath' in entry ? entry.schemaPath : entry.key
311
+ });
312
+ };
275
313
  }
276
314
 
277
315
  //# sourceMappingURL=generate.js.map