@sanity/cli 8.21.0 → 8.22.1

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 (80) 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/deployStudioSchemasAndManifestsWorker.js +6 -15
  21. package/dist/actions/deploy/deployStudioSchemasAndManifestsWorker.js.map +1 -1
  22. package/dist/actions/deploy/resolveDeployTarget.js +7 -6
  23. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  24. package/dist/actions/init/project/promptForAppTemplateSetup.js +22 -0
  25. package/dist/actions/init/project/promptForAppTemplateSetup.js.map +1 -1
  26. package/dist/actions/schema/deploySchemas.js.map +1 -1
  27. package/dist/actions/schema/extractSchemaWatcher.js +69 -14
  28. package/dist/actions/schema/extractSchemaWatcher.js.map +1 -1
  29. package/dist/actions/schema/listSchemas.js +2 -3
  30. package/dist/actions/schema/listSchemas.js.map +1 -1
  31. package/dist/actions/schema/updateWorkspaceSchema.js.map +1 -1
  32. package/dist/actions/typegen/generateResourceTypes.js +11 -8
  33. package/dist/actions/typegen/generateResourceTypes.js.map +1 -1
  34. package/dist/actions/typegen/watchResourceTypes.js +208 -0
  35. package/dist/actions/typegen/watchResourceTypes.js.map +1 -0
  36. package/dist/actions/undeploy/runUndeploy.js +14 -8
  37. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  38. package/dist/commands/codemod.js +15 -4
  39. package/dist/commands/codemod.js.map +1 -1
  40. package/dist/commands/context/get.js +3 -8
  41. package/dist/commands/context/get.js.map +1 -1
  42. package/dist/commands/context/imports/download.js +3 -8
  43. package/dist/commands/context/imports/download.js.map +1 -1
  44. package/dist/commands/context/imports/get.js +3 -8
  45. package/dist/commands/context/imports/get.js.map +1 -1
  46. package/dist/commands/context/imports/list.js +3 -8
  47. package/dist/commands/context/imports/list.js.map +1 -1
  48. package/dist/commands/context/jobs/get.js +8 -8
  49. package/dist/commands/context/jobs/get.js.map +1 -1
  50. package/dist/commands/context/list.js +2 -6
  51. package/dist/commands/context/list.js.map +1 -1
  52. package/dist/commands/deploy.js +1 -0
  53. package/dist/commands/deploy.js.map +1 -1
  54. package/dist/commands/doctor.js +2 -1
  55. package/dist/commands/doctor.js.map +1 -1
  56. package/dist/commands/openapi/list.js +2 -4
  57. package/dist/commands/openapi/list.js.map +1 -1
  58. package/dist/commands/projects/create.js +3 -6
  59. package/dist/commands/projects/create.js.map +1 -1
  60. package/dist/commands/schemas/list.js +1 -3
  61. package/dist/commands/schemas/list.js.map +1 -1
  62. package/dist/commands/tokens/create.js +2 -5
  63. package/dist/commands/tokens/create.js.map +1 -1
  64. package/dist/commands/tokens/list.js +2 -6
  65. package/dist/commands/tokens/list.js.map +1 -1
  66. package/dist/commands/tokens/rotate.js +2 -5
  67. package/dist/commands/tokens/rotate.js.map +1 -1
  68. package/dist/commands/typegen/generate.js +83 -45
  69. package/dist/commands/typegen/generate.js.map +1 -1
  70. package/dist/commands/undeploy.js +1 -0
  71. package/dist/commands/undeploy.js.map +1 -1
  72. package/dist/commands/whoami.js +5 -11
  73. package/dist/commands/whoami.js.map +1 -1
  74. package/dist/exports/invokeSanityCli/index.js +26 -6
  75. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  76. package/dist/generated/apiRoutes.js +11 -26
  77. package/dist/generated/apiRoutes.js.map +1 -1
  78. package/dist/telemetry/init.telemetry.js.map +1 -1
  79. package/oclif.manifest.json +2340 -2311
  80. package/package.json +6 -5
@@ -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":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,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,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,GAAGP,oBAAoB;YACrBI,aAAa;YACbI,WAAW;gBAAC;aAAa;YACzBC,WAAW;QACb,EAAE;QACF,GAAGR,iBAAiB;YAClBG,aAAa;YACbK,WAAW;QACb,EAAE;QACFC,MAAMnB,MAAMoB,OAAO,CAAC;YAClBC,SAAS;YACTR,aAAa;QACf;IACF,EAAC;IAED,OAAgBS,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACP,KAAK,EAAC,GAAG,MAAM,IAAI,CAACQ,KAAK,CAACZ;QACjC,MAAM,EAACO,IAAI,EAAC,GAAGH;QACf,MAAMS,aAAaN,QAAQ;QAE3B,MAAMO,QAAQ,MAAMnB,kBAAkB;YACpCoB,cAAc,IAAI,CAACA,YAAY,CAACC,IAAI,CAAC,IAAI;YACzCC,OAAO;YACPC,cAAcd,MAAMc,YAAY;QAClC;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMzB,UAAUoB;QAC3B,EAAE,OAAOM,OAAO;YACd,MAAMC,UAAU7B,gBAAgB4B;YAChCrB,eAAe,CAAC,0BAA0B,EAAEe,MAAMQ,YAAY,CAAC,CAAC,EAAER,MAAMS,UAAU,EAAE,EAAEH;YACtF,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACG,MAAMnC,UAAUoC,aAAa;YAAA;QACvF;QAEA,IAAIZ,YAAY;YACd,IAAI,CAACa,GAAG,CAACC,KAAKC,SAAS,CAACT,QAAQ,MAAM;YACtC;QACF;QAEA,IAAIA,OAAOU,MAAM,KAAK,GAAG;YACvB,IAAI,CAACH,GAAG,CAAC,CAAC,6BAA6B,EAAEZ,MAAMQ,YAAY,CAAC,CAAC,CAAC;YAC9D;QACF;QAEA,MAAMQ,QAAQ,IAAIlC,MAAM;YACtBmC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAI;gBAC3C;oBACEF,WAAW;oBACXC,MAAM;oBACNC,OAAOpB,MAAMQ,YAAY,KAAK,iBAAiB,WAAW;gBAC5D;gBACA;oBAACU,WAAW;oBAAQC,MAAM;oBAAWC,OAAO;gBAAS;aACtD;YACDA,OAAO,CAAC,MAAM,EAAEf,OAAOU,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMM,SAAShB,OAAQ;YAC1B,MAAMiB,QAAQ3C,kBAAkB0C,OAAOrB;YAEvCgB,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,CAACV,GAAG,CAACI,MAAMa,MAAM;IACvB;AACF"}
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
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {formatPath} from '../../actions/typegen/formatPath.js'\nimport {\n generateResourceTypes,\n resolveResourceSchemas,\n} from '../../actions/typegen/generateResourceTypes.js'\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {\n parseTypegenResources,\n type TypegenResourcesConfig,\n} from '../../actions/typegen/parseTypegenResources.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.\n- 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()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n resources?: TypegenResourcesConfig\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n const resources = parseTypegenResources(config.typegen, workDir)\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n const resources = parseTypegenResources(config.typegen, workDir)\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {\n config: typegenConfig,\n resources,\n type: typegenConfigMethod,\n workDir,\n } = await this.getConfig()\n trace.start()\n\n if (resources) {\n for (const warning of resources.warnings) {\n this.output.warn(warning)\n }\n\n const resourceSpin = spinner({})\n spin = resourceSpin\n const resolved = await resolveResourceSchemas({\n onResolved: (entry) => {\n resourceSpin.succeed(\n 'schemaPath' in entry\n ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}`\n : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`,\n )\n },\n onResolving: (resource, key) => {\n resourceSpin.start(\n resource.schema === undefined\n ? `Fetching the schema bound to ${key}…`\n : `Checking the schema file for ${key}…`,\n )\n },\n resources: resources.resources,\n workDir,\n })\n\n const results = await generateResourceTypes({\n config: typegenConfig,\n onProgress: (entry) => {\n resourceSpin.start(`Generating types for ${entry.key}…`)\n return createTypegenProgressRenderer(resourceSpin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: entry.resource.generates,\n schema: 'schemaPath' in entry ? entry.schemaPath : entry.key,\n })\n },\n resolved,\n workDir,\n })\n\n for (const {result} of results) {\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...omit(result, 'code', 'duration'),\n })\n }\n trace.complete()\n return\n }\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, resources, workDir} = await this.getConfig()\n if (resources) {\n this.error(\n 'Watch mode does not support typegen.resources yet. Run \"sanity typegen generate\" without --watch.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({}).start('Loading schema…')\n spin = watchSpin\n const rendererContext = {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }\n let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n\n const typegenWatcher = runTypegenWatcher({\n config: typegenConfig,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n // Errors already reported with `this.error()` keep their own exit code.\n if (error instanceof CLIError) throw error\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","formatPath","generateResourceTypes","resolveResourceSchemas","parseTypegenConfig","parseTypegenResources","createTypegenProgressRenderer","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","resources","path","type","succeed","trace","telemetry","typegenConfig","typegenConfigMethod","warning","warnings","output","resourceSpin","resolved","onResolved","entry","schemaPath","key","schemaVersion","onResolving","resource","schema","undefined","results","onProgress","formatGeneratedCode","generates","result","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","traceStats","isSpinning","String","message","USAGE_ERROR","resolve","promise","Promise","res","watchSpin","rendererContext","renderProgress","typegenWatcher","event","stop","process","off","step","getStats","on"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,SAAS,QAAO,YAAW;AAEnC,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,QAAQ,QAAO,qBAAoB;AAC3C,SAAQC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AACzD,SAAQC,OAAO,QAA6B,sBAAqB;AACjE,SACEC,UAAU,EACVC,kBAAkB,EAClBC,iBAAiB,EAEjBC,qBAAqB,EACrBC,mBAAmB,QACd,kBAAiB;AACxB,OAAOC,UAAU,oBAAmB;AACpC,OAAOC,UAAU,oBAAmB;AAEpC,SAAQC,UAAU,QAAO,sCAAqC;AAC9D,SACEC,qBAAqB,EACrBC,sBAAsB,QACjB,iDAAgD;AACvD,SAAQC,kBAAkB,QAAO,8CAA6C;AAC9E,SACEC,qBAAqB,QAEhB,iDAAgD;AACvD,SAAQC,6BAA6B,QAAO,iDAAgD;AAE5F,MAAMC,cAAc,CAAC;;AAErB,EAAEnB,UAAU,QAAQ,kBAAkB;;;;;;;;;;;;;;AActC,EAAEA,UAAU,QAAQ,SAAS;;oNAEuL,CAAC,CAACoB,IAAI;AAE1N,OAAO,MAAMC,+BAA+BjB;IAC1C,OAAgBe,cAAcA,YAAW;IAEzC,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa,CAAC,uHAAuH,CAAC;QACxI;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,eAAevB,MAAMwB,MAAM,CAAC;YAC1BN,aACE;QACJ;QACAO,OAAOzB,MAAM0B,OAAO,CAAC;YACnBC,SAAS;YACTT,aAAa;QACf;IACF,EAAC;IAED,OAAgBU,gBAA0B;QAAC;KAAmB,CAAA;IAE9D,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACV;QAEjC,IAAIG,MAAME,KAAK,EAAE;YACf,MAAM,IAAI,CAACM,UAAU;YACrB;QACF;QAEA,MAAM,IAAI,CAACC,SAAS;IACtB;IAEA,MAAcC,YAMX;QACD,MAAMC,OAAO9B,QAAQ,CAAC,GAAG+B,KAAK,CAAC;QAE/B,IAAI;YACF,MAAM,EAACZ,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACV;YACjC,MAAMgB,UAAU,MAAM,IAAI,CAACC,cAAc;YACzC,MAAMC,SAAS,MAAM,IAAI,CAACC,YAAY;YAEtC,MAAMC,aAAajB,KAAK,CAAC,cAAc;YACvC,MAAMkB,UAAUL,QAAQM,SAAS;YAEjC,MAAMC,mBAAmBH,cAAc;YACvC,IAAII,kBAAkB;YAEtB,IAAI;gBACF,MAAMC,OAAO,MAAM/C,KAAK6C;gBACxBC,kBAAkBC,KAAKC,MAAM;YAC/B,EAAE,OAAOC,KAAK;gBACZ,IAAIA,eAAeC,SAAS,UAAUD,OAAOA,IAAIE,IAAI,KAAK,YAAYT,YAAY;oBAChFN,KAAKgB,IAAI;oBACT,IAAI,CAACC,KAAK,CAAC,CAAC,+BAA+B,EAAEX,YAAY,EAAE;wBACzDY,MAAMlD,UAAUmD,aAAa;oBAC/B;gBACF;gBAEA,IAAIN,eAAeC,SAAS,UAAUD,OAAOA,IAAIE,IAAI,KAAK,UAAU;oBAClEf,KAAKgB,IAAI;oBACT,IAAI,CAACC,KAAK,CAAC,CAAC,mDAAmD,EAAER,kBAAkB,EAAE;wBACnFS,MAAMlD,UAAUmD,aAAa;oBAC/B;gBACF;YACF;YAEA,IAAIf,QAAQgB,WAAWV,iBAAiB;gBACtCV,KAAKqB,IAAI,CACPxD,UACE,UACA,CAAC;;;IAGT,CAAC;gBAIG,MAAMyD,YAAYxC,sBAAsBsB,OAAOgB,OAAO,EAAEb;gBACxD,OAAO;oBACLH,QAAQkB,WAAWlB,UAAUvB,mBAAmBuB,OAAOgB,OAAO,IAAI,CAAC;oBACnEG,MAAMrB,QAAQqB,IAAI;oBAClBD;oBACAE,MAAM;oBACNjB;gBACF;YACF;YAEA,IAAIG,iBAAiB;gBACnBV,KAAKqB,IAAI,CACPxD,UACE,UACA,CAAC;;iFAEoE,CAAC;gBAG1E,OAAO;oBACLuC,QAAQ,MAAMjC,WAAWsC;oBACzBc,MAAMd;oBACNe,MAAM;oBACNjB;gBACF;YACF;YAEA,MAAMe,YAAYxC,sBAAsBsB,OAAOgB,OAAO,EAAEb;YACxDP,KAAKyB,OAAO,CAAC,CAAC,gCAAgC,CAAC;YAE/C,OAAO;gBACLrB,QAAQkB,WAAWlB,UAAUvB,mBAAmBuB,OAAOgB,OAAO,IAAI,CAAC;gBACnEG,MAAMrB,QAAQqB,IAAI;gBAClBD;gBACAE,MAAM;gBACNjB;YACF;QACF,EAAE,OAAOM,KAAK;YACZ,wEAAwE;YACxE,sEAAsE;YACtE,6DAA6D;YAC7D,IAAIA,eAAe9C,UAAU,MAAM8C;YACnCb,KAAKgB,IAAI;YACT,IAAI,CAACC,KAAK,CAAC,CAAC,yCAAyC,EAAEJ,KAAK,EAAE;gBAC5DK,MAAMlD,UAAUmD,aAAa;YAC/B;QACF;IACF;IAEA,MAAcrB,YAA2B;QACvC,MAAM4B,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAACnD;QACnC,IAAIyB;QAEJ,IAAI;YACF,MAAM,EACJI,QAAQwB,aAAa,EACrBN,SAAS,EACTE,MAAMK,mBAAmB,EACzBtB,OAAO,EACR,GAAG,MAAM,IAAI,CAACR,SAAS;YACxB2B,MAAMzB,KAAK;YAEX,IAAIqB,WAAW;gBACb,KAAK,MAAMQ,WAAWR,UAAUS,QAAQ,CAAE;oBACxC,IAAI,CAACC,MAAM,CAACX,IAAI,CAACS;gBACnB;gBAEA,MAAMG,eAAe/D,QAAQ,CAAC;gBAC9B8B,OAAOiC;gBACP,MAAMC,WAAW,MAAMtD,uBAAuB;oBAC5CuD,YAAY,CAACC;wBACXH,aAAaR,OAAO,CAClB,gBAAgBW,QACZ,CAAC,MAAM,EAAE1D,WAAW0D,MAAMC,UAAU,EAAE,KAAK,EAAED,MAAME,GAAG,EAAE,GACxD,CAAC,4BAA4B,EAAEF,MAAME,GAAG,CAAC,EAAE,EAAEF,MAAMG,aAAa,CAAC,CAAC,CAAC;oBAE3E;oBACAC,aAAa,CAACC,UAAUH;wBACtBL,aAAahC,KAAK,CAChBwC,SAASC,MAAM,KAAKC,YAChB,CAAC,6BAA6B,EAAEL,IAAI,CAAC,CAAC,GACtC,CAAC,6BAA6B,EAAEA,IAAI,CAAC,CAAC;oBAE9C;oBACAhB,WAAWA,UAAUA,SAAS;oBAC9Bf;gBACF;gBAEA,MAAMqC,UAAU,MAAMjE,sBAAsB;oBAC1CyB,QAAQwB;oBACRiB,YAAY,CAACT;wBACXH,aAAahC,KAAK,CAAC,CAAC,qBAAqB,EAAEmC,MAAME,GAAG,CAAC,CAAC,CAAC;wBACvD,OAAOvD,8BAA8BkD,cAAc;4BACjDa,qBAAqBlB,cAAckB,mBAAmB;4BACtDC,WAAWX,MAAMK,QAAQ,CAACM,SAAS;4BACnCL,QAAQ,gBAAgBN,QAAQA,MAAMC,UAAU,GAAGD,MAAME,GAAG;wBAC9D;oBACF;oBACAJ;oBACA3B;gBACF;gBAEA,KAAK,MAAM,EAACyC,MAAM,EAAC,IAAIJ,QAAS;oBAC9BlB,MAAMuB,GAAG,CAAC;wBACRC,cAAcrB;wBACdsB,6BAA6BvB,cAAcwB,qBAAqB;wBAChE,GAAG5E,KAAKwE,QAAQ,QAAQ,WAAW;oBACrC;gBACF;gBACAtB,MAAM2B,QAAQ;gBACd;YACF;YAEArD,OAAO9B,QAAQ,CAAC,GAAG+B,KAAK,CAAC;YACzB,MAAM+C,SAAS,MAAM5E,mBAAmB;gBACtCgC,QAAQwB;gBACRiB,YAAY9D,8BAA8BiB,MAAM;oBAC9C8C,qBAAqBlB,cAAckB,mBAAmB;oBACtDC,WAAWnB,cAAcmB,SAAS;oBAClCL,QAAQd,cAAcc,MAAM;gBAC9B;gBACAnC;YACF;YAEA,MAAM+C,aAAa9E,KAAKwE,QAAQ,QAAQ;YAExCtB,MAAMuB,GAAG,CAAC;gBACRC,cAAcrB;gBACdsB,6BAA6BvB,cAAcwB,qBAAqB;gBAChE,GAAGE,UAAU;YACf;YACA5B,MAAM2B,QAAQ;QAChB,EAAE,OAAOpC,OAAO;YACd,IAAIjB,MAAMuD,YAAY;gBACpBvD,KAAKgB,IAAI;YACX;YACAU,MAAMT,KAAK,CAACA,iBAAiBH,QAAQG,QAAQ,IAAIH,MAAM0C,OAAOvC;YAC9D,IAAI,CAACA,KAAK,CAAC,GAAGA,iBAAiBH,QAAQG,MAAMwC,OAAO,GAAG,iBAAiB,EAAE;gBACxEvC,MAAMlD,UAAUmD,aAAa;YAC/B;QACF;IACF;IAEA,MAActB,aAA4B;QACxC,MAAM6B,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAACpD;QACnC,IAAI0B;QAEJ,IAAI;YACF,MAAM,EAACI,QAAQwB,aAAa,EAAEN,SAAS,EAAEf,OAAO,EAAC,GAAG,MAAM,IAAI,CAACR,SAAS;YACxE,IAAIuB,WAAW;gBACb,IAAI,CAACL,KAAK,CACR,qGACA;oBAACC,MAAMlD,UAAU0F,WAAW;gBAAA;YAEhC;YACAhC,MAAMzB,KAAK;YAEX,IAAI0D,UAAsB,KAAO;YACjC,MAAMC,UAAU,IAAIC,QAAc,CAACC;gBACjCH,UAAUG;YACZ;YAEA,MAAMC,YAAY7F,QAAQ,CAAC,GAAG+B,KAAK,CAAC;YACpCD,OAAO+D;YACP,MAAMC,kBAAkB;gBACtBlB,qBAAqBlB,cAAckB,mBAAmB;gBACtDC,WAAWnB,cAAcmB,SAAS;gBAClCL,QAAQd,cAAcc,MAAM;YAC9B;YACA,IAAIuB,iBAAiBlF,8BAA8BgF,WAAWC;YAE9D,MAAME,iBAAiB7F,kBAAkB;gBACvC+B,QAAQwB;gBACRiB,YAAY,CAACsB;oBACX,mEAAmE;oBACnE,iEAAiE;oBACjE,IAAIA,MAAM3C,IAAI,KAAK,gBAAgB;wBACjCyC,iBAAiBlF,8BAA8BgF,WAAWC;oBAC5D;oBACAC,eAAeE;gBACjB;gBACA5D;YACF;YAEA,MAAM6D,OAAO3F,KAAK;gBAChB4F,QAAQC,GAAG,CAAC,UAAUF;gBACtBC,QAAQC,GAAG,CAAC,WAAWF;gBAEvB,IAAIL,UAAUR,UAAU,EAAE;oBACxBQ,UAAUK,IAAI;gBAChB;gBAEA1C,MAAMuB,GAAG,CAAC;oBACRsB,MAAM;oBACN,GAAGL,eAAeM,QAAQ,EAAE;gBAC9B;gBACA9C,MAAM2B,QAAQ;gBAEd,IAAI;oBACF,MAAMa,eAAeE,IAAI;gBAC3B,EAAE,OAAM;gBACN,qEAAqE;gBACrE,oDAAoD;gBACtD;gBACAT;YACF;YAEAU,QAAQI,EAAE,CAAC,UAAUL;YACrBC,QAAQI,EAAE,CAAC,WAAWL;YAEtB,MAAMR;QACR,EAAE,OAAO3C,OAAO;YACd,IAAIjB,MAAMuD,YAAY;gBACpBvD,KAAKgB,IAAI;YACX;YACAU,MAAMT,KAAK,CAACA,iBAAiBH,QAAQG,QAAQ,IAAIH,MAAM0C,OAAOvC;YAC9D,wEAAwE;YACxE,IAAIA,iBAAiBlD,UAAU,MAAMkD;YACrC,IAAI,CAACA,KAAK,CAAC,GAAGA,iBAAiBH,QAAQG,MAAMwC,OAAO,GAAG,iBAAiB,EAAE;gBACxEvC,MAAMlD,UAAUmD,aAAa;YAC/B;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n type TypegenProgressEvent,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {formatPath} from '../../actions/typegen/formatPath.js'\nimport {\n generateResourceTypes,\n type ResolvedResource,\n resolveResourceSchemas,\n} from '../../actions/typegen/generateResourceTypes.js'\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {\n parseTypegenResources,\n type TypegenResourcesConfig,\n} from '../../actions/typegen/parseTypegenResources.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\nimport {\n type ResourceTypesWatcher,\n watchResourceTypes,\n} from '../../actions/typegen/watchResourceTypes.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.\n- 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()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n resources?: TypegenResourcesConfig\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n const resources = parseTypegenResources(config.typegen, workDir)\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n const resources = parseTypegenResources(config.typegen, workDir)\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n /**\n * Prints the resources' configuration warnings, then locates every resource's schema, reporting\n * each one on the spinner.\n */\n private async resolveResources(\n resources: TypegenResourcesConfig,\n spin: SpinnerInstance,\n workDir: string,\n {checkSchemaFiles}: {checkSchemaFiles: boolean},\n ): Promise<ResolvedResource[]> {\n for (const warning of resources.warnings) {\n this.output.warn(warning)\n }\n\n return resolveResourceSchemas({\n checkSchemaFiles,\n onResolved: (entry) => {\n spin.succeed(\n 'schemaPath' in entry\n ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}`\n : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`,\n )\n },\n onResolving: (resource, key) => {\n spin.start(\n resource.schema === undefined\n ? `Fetching the schema bound to ${key}…`\n : `Checking the schema file for ${key}…`,\n )\n },\n resources: resources.resources,\n workDir,\n })\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {\n config: typegenConfig,\n resources,\n type: typegenConfigMethod,\n workDir,\n } = await this.getConfig()\n trace.start()\n\n if (resources) {\n const resourceSpin = spinner({})\n spin = resourceSpin\n const resolved = await this.resolveResources(resources, resourceSpin, workDir, {\n checkSchemaFiles: true,\n })\n\n const results = await generateResourceTypes({\n config: typegenConfig,\n onProgress: createResourceProgressHandler(resourceSpin, typegenConfig),\n resolved,\n workDir,\n })\n\n for (const {result} of results) {\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...omit(result, 'code', 'duration'),\n })\n }\n trace.complete()\n return\n }\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, resources, workDir} = await this.getConfig()\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({})\n spin = watchSpin\n const typegenWatcher = resources\n ? await this.startResourceWatcher(typegenConfig, resources, watchSpin, workDir)\n : this.startSchemaWatcher(typegenConfig, watchSpin, workDir)\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n // Errors already reported with `this.error()` keep their own exit code.\n if (error instanceof CLIError) throw error\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n /**\n * Locates every resource's schema once, then generates on each query or local schema change.\n * A schema bound to a dataset is fetched only here, so a schema deployed while the watcher runs\n * is used after a restart.\n */\n private async startResourceWatcher(\n config: TypeGenConfig,\n resources: TypegenResourcesConfig,\n spin: SpinnerInstance,\n workDir: string,\n ): Promise<ResourceTypesWatcher> {\n // A missing local schema file fails that resource's generation until the file appears,\n // instead of ending the watcher.\n const resolved = await this.resolveResources(resources, spin, workDir, {\n checkSchemaFiles: false,\n })\n\n return watchResourceTypes({\n config,\n onChange: (event, relativePath) => {\n this.output.log(`[${new Date().toLocaleTimeString()}] ${event}: ${relativePath}`)\n },\n onError: (error) => {\n spin.fail(error instanceof Error ? error.message : String(error))\n },\n onProgress: createResourceProgressHandler(spin, config),\n resolved,\n workDir,\n })\n }\n\n private startSchemaWatcher(\n config: TypeGenConfig,\n spin: SpinnerInstance,\n workDir: string,\n ): ReturnType<typeof runTypegenWatcher> {\n spin.start('Loading schema…')\n const rendererContext = {\n formatGeneratedCode: config.formatGeneratedCode,\n generates: config.generates,\n schema: config.schema,\n }\n let renderProgress = createTypegenProgressRenderer(spin, rendererContext)\n\n return runTypegenWatcher({\n config,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(spin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n }\n}\n\n/**\n * Returns the progress handler for one resource's generation, which starts with a line naming\n * the resource. The renderer keeps per-run state, so each generation gets a new one.\n */\nfunction createResourceProgressHandler(\n spin: SpinnerInstance,\n config: TypeGenConfig,\n): (entry: ResolvedResource) => (event: TypegenProgressEvent) => void {\n return (entry) => {\n spin.start(`Generating types for ${entry.key}…`)\n return createTypegenProgressRenderer(spin, {\n formatGeneratedCode: config.formatGeneratedCode,\n generates: entry.resource.generates,\n schema: 'schemaPath' in entry ? entry.schemaPath : entry.key,\n })\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","formatPath","generateResourceTypes","resolveResourceSchemas","parseTypegenConfig","parseTypegenResources","createTypegenProgressRenderer","watchResourceTypes","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","resources","path","type","succeed","resolveResources","checkSchemaFiles","warning","warnings","output","onResolved","entry","schemaPath","key","schemaVersion","onResolving","resource","schema","undefined","trace","telemetry","typegenConfig","typegenConfigMethod","resourceSpin","resolved","results","onProgress","createResourceProgressHandler","result","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","formatGeneratedCode","generates","traceStats","isSpinning","String","message","resolve","promise","Promise","res","watchSpin","typegenWatcher","startResourceWatcher","startSchemaWatcher","stop","process","off","step","getStats","on","onChange","event","relativePath","Date","toLocaleTimeString","onError","rendererContext","renderProgress"],"mappings":"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"}
@@ -13,6 +13,7 @@ export class UndeployCommand extends SanityCommand {
13
13
  })
14
14
  };
15
15
  static description = 'Removes the deployed Sanity Studio/App from Sanity hosting';
16
+ static enableJsonFlag = true;
16
17
  static examples = [
17
18
  {
18
19
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type CliConfig, exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {type UndeployAdapter} from '@sanity/cli-core/undeploy'\nimport {getWorkbench, resolveWorkbenchConfig} from '@sanity/workbench-cli/deploy'\nimport {createWorkbenchUndeployAdapter} from '@sanity/workbench-cli/undeploy'\n\nimport {\n createAppUndeployAdapter,\n createStudioUndeployAdapter,\n} from '../actions/undeploy/adapters.js'\nimport {runUndeploy} from '../actions/undeploy/runUndeploy.js'\nimport {getAppId} from '../util/appId.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override args = {\n appId: Args.string({\n description:\n 'ID of the application to undeploy. Overrides `deployment.appId` in sanity.cli.ts',\n }),\n }\n\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Undeploy the studio or application after confirming',\n },\n {\n command: '<%= config.bin %> <%= command.id %> abc123',\n description: 'Undeploy the studio or application with the given ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --dry-run',\n description: 'Report what would be undeployed without deleting anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --yes',\n description: 'Undeploy without prompting and report the result as JSON',\n },\n ]\n\n static override flags = {\n 'dry-run': Flags.boolean({\n default: false,\n description: 'Report what would be undeployed without deleting anything',\n }),\n json: Flags.boolean({\n char: 'j',\n default: false,\n description: 'Output the result as JSON',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(UndeployCommand)\n\n const projectConfig = await this.getCliConfig()\n const isApp = determineIsApp(projectConfig)\n if (args.appId) this.warnIfOverridingConfig(args.appId, projectConfig, isApp)\n // An explicit ID stands in for `deployment.appId`, which every adapter\n // already prefers over `studioHost` and the deprecated `app.id`.\n const cliConfig = args.appId\n ? {...projectConfig, deployment: {...projectConfig.deployment, appId: args.appId}}\n : projectConfig\n\n // Workbench apps and configs deploy through Brett, so they undeploy through\n // it too; plain projects keep the user-applications backend.\n const workbench = getWorkbench(cliConfig)\n const config = resolveWorkbenchConfig(cliConfig)\n if (args.appId && config) {\n this.error('An app ID cannot be used to undeploy a config. Run without the argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const adapter: UndeployAdapter =\n workbench || config\n ? createWorkbenchUndeployAdapter({\n appId: getAppId(cliConfig),\n config: config ?? undefined,\n organizationId: cliConfig.app?.organizationId,\n type: isApp ? 'coreApp' : 'studio',\n workbench: workbench ?? undefined,\n })\n : isApp\n ? createAppUndeployAdapter(cliConfig)\n : createStudioUndeployAdapter(cliConfig)\n\n await runUndeploy({flags, isUnattended: this.isUnattended(), output: this.output}, adapter)\n }\n\n private warnIfOverridingConfig(appId: string, cliConfig: CliConfig, isApp: boolean): void {\n const configuredAppId = getAppId(cliConfig)\n if (configuredAppId) {\n if (configuredAppId !== appId) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of \"${configuredAppId}\" configured in sanity.cli.ts`,\n )\n }\n return\n }\n\n if (!isApp && cliConfig.studioHost) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of studio host \"${cliConfig.studioHost}\" configured in sanity.cli.ts`,\n )\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","getWorkbench","resolveWorkbenchConfig","createWorkbenchUndeployAdapter","createAppUndeployAdapter","createStudioUndeployAdapter","runUndeploy","getAppId","determineIsApp","UndeployCommand","args","appId","string","description","examples","command","flags","boolean","default","json","char","yes","run","parse","projectConfig","getCliConfig","isApp","warnIfOverridingConfig","cliConfig","deployment","workbench","config","error","exit","USAGE_ERROR","adapter","undefined","organizationId","app","type","isUnattended","output","configuredAppId","warn","studioHost"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAwBC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzE,SAAQC,YAAY,EAAEC,sBAAsB,QAAO,+BAA8B;AACjF,SAAQC,8BAA8B,QAAO,iCAAgC;AAE7E,SACEC,wBAAwB,EACxBC,2BAA2B,QACtB,kCAAiC;AACxC,SAAQC,WAAW,QAAO,qCAAoC;AAC9D,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,wBAAwBT;IACnC,OAAgBU,OAAO;QACrBC,OAAOd,KAAKe,MAAM,CAAC;YACjBC,aACE;QACJ;IACF,EAAC;IAED,OAAgBA,cAAc,6DAA4D;IAE1F,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtB,WAAWlB,MAAMmB,OAAO,CAAC;YACvBC,SAAS;YACTL,aAAa;QACf;QACAM,MAAMrB,MAAMmB,OAAO,CAAC;YAClBG,MAAM;YACNF,SAAS;YACTL,aAAa;QACf;QACAQ,KAAKvB,MAAMmB,OAAO,CAAC;YACjBG,MAAM;YACNF,SAAS;YACTL,aACE;QACJ;IACF,EAAC;IAED,MAAaS,MAAqB;QAChC,MAAM,EAACZ,IAAI,EAAEM,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACd;QAEvC,MAAMe,gBAAgB,MAAM,IAAI,CAACC,YAAY;QAC7C,MAAMC,QAAQlB,eAAegB;QAC7B,IAAId,KAAKC,KAAK,EAAE,IAAI,CAACgB,sBAAsB,CAACjB,KAAKC,KAAK,EAAEa,eAAeE;QACvE,uEAAuE;QACvE,iEAAiE;QACjE,MAAME,YAAYlB,KAAKC,KAAK,GACxB;YAAC,GAAGa,aAAa;YAAEK,YAAY;gBAAC,GAAGL,cAAcK,UAAU;gBAAElB,OAAOD,KAAKC,KAAK;YAAA;QAAC,IAC/Ea;QAEJ,4EAA4E;QAC5E,6DAA6D;QAC7D,MAAMM,YAAY7B,aAAa2B;QAC/B,MAAMG,SAAS7B,uBAAuB0B;QACtC,IAAIlB,KAAKC,KAAK,IAAIoB,QAAQ;YACxB,IAAI,CAACC,KAAK,CAAC,4EAA4E;gBACrFC,MAAMlC,UAAUmC,WAAW;YAC7B;QACF;QAEA,MAAMC,UACJL,aAAaC,SACT5B,+BAA+B;YAC7BQ,OAAOJ,SAASqB;YAChBG,QAAQA,UAAUK;YAClBC,gBAAgBT,UAAUU,GAAG,EAAED;YAC/BE,MAAMb,QAAQ,YAAY;YAC1BI,WAAWA,aAAaM;QAC1B,KACAV,QACEtB,yBAAyBwB,aACzBvB,4BAA4BuB;QAEpC,MAAMtB,YAAY;YAACU;YAAOwB,cAAc,IAAI,CAACA,YAAY;YAAIC,QAAQ,IAAI,CAACA,MAAM;QAAA,GAAGN;IACrF;IAEQR,uBAAuBhB,KAAa,EAAEiB,SAAoB,EAAEF,KAAc,EAAQ;QACxF,MAAMgB,kBAAkBnC,SAASqB;QACjC,IAAIc,iBAAiB;YACnB,IAAIA,oBAAoB/B,OAAO;gBAC7B,IAAI,CAAC8B,MAAM,CAACE,IAAI,CACd,CAAC,cAAc,EAAEhC,MAAM,cAAc,EAAE+B,gBAAgB,6BAA6B,CAAC;YAEzF;YACA;QACF;QAEA,IAAI,CAAChB,SAASE,UAAUgB,UAAU,EAAE;YAClC,IAAI,CAACH,MAAM,CAACE,IAAI,CACd,CAAC,cAAc,EAAEhC,MAAM,0BAA0B,EAAEiB,UAAUgB,UAAU,CAAC,6BAA6B,CAAC;QAE1G;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type CliConfig, exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {type UndeployAdapter} from '@sanity/cli-core/undeploy'\nimport {getWorkbench, resolveWorkbenchConfig} from '@sanity/workbench-cli/deploy'\nimport {createWorkbenchUndeployAdapter} from '@sanity/workbench-cli/undeploy'\n\nimport {\n createAppUndeployAdapter,\n createStudioUndeployAdapter,\n} from '../actions/undeploy/adapters.js'\nimport {runUndeploy} from '../actions/undeploy/runUndeploy.js'\nimport {getAppId} from '../util/appId.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override args = {\n appId: Args.string({\n description:\n 'ID of the application to undeploy. Overrides `deployment.appId` in sanity.cli.ts',\n }),\n }\n\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Undeploy the studio or application after confirming',\n },\n {\n command: '<%= config.bin %> <%= command.id %> abc123',\n description: 'Undeploy the studio or application with the given ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --dry-run',\n description: 'Report what would be undeployed without deleting anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --yes',\n description: 'Undeploy without prompting and report the result as JSON',\n },\n ]\n\n static override flags = {\n 'dry-run': Flags.boolean({\n default: false,\n description: 'Report what would be undeployed without deleting anything',\n }),\n json: Flags.boolean({\n char: 'j',\n default: false,\n description: 'Output the result as JSON',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(UndeployCommand)\n\n const projectConfig = await this.getCliConfig()\n const isApp = determineIsApp(projectConfig)\n if (args.appId) this.warnIfOverridingConfig(args.appId, projectConfig, isApp)\n // An explicit ID stands in for `deployment.appId`, which every adapter\n // already prefers over `studioHost` and the deprecated `app.id`.\n const cliConfig = args.appId\n ? {...projectConfig, deployment: {...projectConfig.deployment, appId: args.appId}}\n : projectConfig\n\n // Workbench apps and configs deploy through Brett, so they undeploy through\n // it too; plain projects keep the user-applications backend.\n const workbench = getWorkbench(cliConfig)\n const config = resolveWorkbenchConfig(cliConfig)\n if (args.appId && config) {\n this.error('An app ID cannot be used to undeploy a config. Run without the argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const adapter: UndeployAdapter =\n workbench || config\n ? createWorkbenchUndeployAdapter({\n appId: getAppId(cliConfig),\n config: config ?? undefined,\n organizationId: cliConfig.app?.organizationId,\n type: isApp ? 'coreApp' : 'studio',\n workbench: workbench ?? undefined,\n })\n : isApp\n ? createAppUndeployAdapter(cliConfig)\n : createStudioUndeployAdapter(cliConfig)\n\n await runUndeploy({flags, isUnattended: this.isUnattended(), output: this.output}, adapter)\n }\n\n private warnIfOverridingConfig(appId: string, cliConfig: CliConfig, isApp: boolean): void {\n const configuredAppId = getAppId(cliConfig)\n if (configuredAppId) {\n if (configuredAppId !== appId) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of \"${configuredAppId}\" configured in sanity.cli.ts`,\n )\n }\n return\n }\n\n if (!isApp && cliConfig.studioHost) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of studio host \"${cliConfig.studioHost}\" configured in sanity.cli.ts`,\n )\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","getWorkbench","resolveWorkbenchConfig","createWorkbenchUndeployAdapter","createAppUndeployAdapter","createStudioUndeployAdapter","runUndeploy","getAppId","determineIsApp","UndeployCommand","args","appId","string","description","enableJsonFlag","examples","command","flags","boolean","default","json","char","yes","run","parse","projectConfig","getCliConfig","isApp","warnIfOverridingConfig","cliConfig","deployment","workbench","config","error","exit","USAGE_ERROR","adapter","undefined","organizationId","app","type","isUnattended","output","configuredAppId","warn","studioHost"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { Flags } from '@oclif/core';
2
1
  import { exitCodes, getCliTokenInfo, SanityCommand } from '@sanity/cli-core';
3
2
  import { isHttpError } from '@sanity/client';
4
3
  import { getProviderName } from '../actions/auth/getProviderName.js';
@@ -7,6 +6,7 @@ import { getSamlProviderId, resolveSSOProvider } from '../actions/whoami/resolve
7
6
  import { getCliUser } from '../services/user.js';
8
7
  export class WhoamiCommand extends SanityCommand {
9
8
  static description = 'Show the user or API token the CLI is authenticated as';
9
+ static enableJsonFlag = true;
10
10
  static examples = [
11
11
  {
12
12
  command: '<%= config.bin %> <%= command.id %>',
@@ -17,14 +17,8 @@ export class WhoamiCommand extends SanityCommand {
17
17
  description: 'Output the current user as JSON, for scripts and agents'
18
18
  }
19
19
  ];
20
- static flags = {
21
- json: Flags.boolean({
22
- default: false,
23
- description: 'Output as JSON'
24
- })
25
- };
26
20
  async run() {
27
- const { flags } = await this.parse(WhoamiCommand);
21
+ const { json } = this.flags;
28
22
  const tokenInfo = await getCliTokenInfo();
29
23
  if (!tokenInfo?.token) {
30
24
  this.error('Not logged in. Run `sanity login` to authenticate.', {
@@ -42,8 +36,8 @@ export class WhoamiCommand extends SanityCommand {
42
36
  });
43
37
  const samlProviderId = getSamlProviderId(user.provider);
44
38
  const sso = samlProviderId ? await resolveSSOProvider(samlProviderId) : undefined;
45
- if (flags.json) {
46
- this.log(JSON.stringify({
39
+ if (json) {
40
+ this.logJson({
47
41
  email: user.email ?? null,
48
42
  id: user.id,
49
43
  name: user.name,
@@ -52,7 +46,7 @@ export class WhoamiCommand extends SanityCommand {
52
46
  sso: sso ?? null
53
47
  } : {},
54
48
  tokenSource: tokenInfo.source
55
- }, null, 2));
49
+ });
56
50
  return;
57
51
  }
58
52
  const padTo = 8 // "Provider" is the longest key
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, getCliTokenInfo, SanityCommand} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {getProviderName} from '../actions/auth/getProviderName.js'\nimport {formatKeyValue} from '../actions/debug/output.js'\nimport {\n getSamlProviderId,\n resolveSSOProvider,\n type SSOProviderInfo,\n} from '../actions/whoami/resolveSSOProvider.js'\nimport {getCliUser} from '../services/user.js'\n\nexport class WhoamiCommand extends SanityCommand<typeof WhoamiCommand> {\n static override description = 'Show the user or API token the CLI is authenticated as'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Show the currently authenticated user',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Output the current user as JSON, for scripts and agents',\n },\n ]\n\n static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output as JSON',\n }),\n }\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(WhoamiCommand)\n\n const tokenInfo = await getCliTokenInfo()\n if (!tokenInfo?.token) {\n this.error('Not logged in. Run `sanity login` to authenticate.', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const user = await getCliUser().catch((err: unknown) => {\n // A stale SANITY_AUTH_TOKEN overrides a valid saved login, so \"run sanity login\" won't help\n if (tokenInfo.source === ENV_TOKEN_SOURCE && isRejectedToken(err)) {\n this.error(\n 'Authentication failed using SANITY_AUTH_TOKEN.\\nUnset it to use your saved login, or replace it with a valid token.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n throw err\n })\n const samlProviderId = getSamlProviderId(user.provider)\n const sso = samlProviderId ? await resolveSSOProvider(samlProviderId) : undefined\n\n if (flags.json) {\n this.log(\n JSON.stringify(\n {\n email: user.email ?? null,\n id: user.id,\n name: user.name,\n provider: user.provider,\n ...(samlProviderId ? {sso: sso ?? null} : {}),\n tokenSource: tokenInfo.source,\n },\n null,\n 2,\n ),\n )\n return\n }\n\n const padTo = 8 // \"Provider\" is the longest key\n this.log(formatKeyValue('Name', user.name, {indent: 0, padTo}))\n if (user.email) {\n this.log(formatKeyValue('Email', user.email, {indent: 0, padTo}))\n }\n this.log(formatKeyValue('ID', user.id, {indent: 0, padTo}))\n this.log(\n formatKeyValue('Provider', formatProvider(user.provider, samlProviderId, sso), {\n indent: 0,\n padTo,\n }),\n )\n if (sso) {\n this.log(formatKeyValue('Org', formatOrganization(sso), {indent: 0, padTo}))\n }\n this.log(formatKeyValue('Token', tokenInfo.source, {indent: 0, padTo}))\n }\n}\n\nconst ENV_TOKEN_SOURCE = 'SANITY_AUTH_TOKEN environment variable'\n\nfunction isRejectedToken(err: unknown): boolean {\n return isHttpError(err) && (err.statusCode === 401 || err.statusCode === 403)\n}\n\nfunction formatProvider(\n provider: string,\n samlProviderId: string | undefined,\n sso: SSOProviderInfo | undefined,\n): string {\n if (provider === 'sanity-token') return 'API token'\n if (samlProviderId) return formatSamlProvider(sso)\n return getProviderName(provider)\n}\n\nfunction formatOrganization(sso: SSOProviderInfo): string {\n if (!sso.organizationSlug) return sso.organizationName\n return `${sso.organizationName} (sanity login --sso ${sso.organizationSlug})`\n}\n\nfunction formatSamlProvider(sso: SSOProviderInfo | undefined): string {\n // Provider names like \"saml\" or \"SSO\" repeat the label without adding anything\n const name = sso?.providerName.trim()\n if (!name || /^(saml|sso|saml sso)$/i.test(name)) return 'SAML SSO'\n return `SAML SSO (${name})`\n}\n"],"names":["Flags","exitCodes","getCliTokenInfo","SanityCommand","isHttpError","getProviderName","formatKeyValue","getSamlProviderId","resolveSSOProvider","getCliUser","WhoamiCommand","description","examples","command","flags","json","boolean","default","run","parse","tokenInfo","token","error","exit","RUNTIME_ERROR","user","catch","err","source","ENV_TOKEN_SOURCE","isRejectedToken","samlProviderId","provider","sso","undefined","log","JSON","stringify","email","id","name","tokenSource","padTo","indent","formatProvider","formatOrganization","statusCode","formatSamlProvider","organizationSlug","organizationName","providerName","trim","test"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import {exitCodes, getCliTokenInfo, SanityCommand} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {getProviderName} from '../actions/auth/getProviderName.js'\nimport {formatKeyValue} from '../actions/debug/output.js'\nimport {\n getSamlProviderId,\n resolveSSOProvider,\n type SSOProviderInfo,\n} from '../actions/whoami/resolveSSOProvider.js'\nimport {getCliUser} from '../services/user.js'\n\nexport class WhoamiCommand extends SanityCommand<typeof WhoamiCommand> {\n static override description = 'Show the user or API token the CLI is authenticated as'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Show the currently authenticated user',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Output the current user as JSON, for scripts and agents',\n },\n ]\n\n public async run(): Promise<void> {\n const {json} = this.flags\n\n const tokenInfo = await getCliTokenInfo()\n if (!tokenInfo?.token) {\n this.error('Not logged in. Run `sanity login` to authenticate.', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const user = await getCliUser().catch((err: unknown) => {\n // A stale SANITY_AUTH_TOKEN overrides a valid saved login, so \"run sanity login\" won't help\n if (tokenInfo.source === ENV_TOKEN_SOURCE && isRejectedToken(err)) {\n this.error(\n 'Authentication failed using SANITY_AUTH_TOKEN.\\nUnset it to use your saved login, or replace it with a valid token.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n throw err\n })\n const samlProviderId = getSamlProviderId(user.provider)\n const sso = samlProviderId ? await resolveSSOProvider(samlProviderId) : undefined\n\n if (json) {\n this.logJson({\n email: user.email ?? null,\n id: user.id,\n name: user.name,\n provider: user.provider,\n ...(samlProviderId ? {sso: sso ?? null} : {}),\n tokenSource: tokenInfo.source,\n })\n return\n }\n\n const padTo = 8 // \"Provider\" is the longest key\n this.log(formatKeyValue('Name', user.name, {indent: 0, padTo}))\n if (user.email) {\n this.log(formatKeyValue('Email', user.email, {indent: 0, padTo}))\n }\n this.log(formatKeyValue('ID', user.id, {indent: 0, padTo}))\n this.log(\n formatKeyValue('Provider', formatProvider(user.provider, samlProviderId, sso), {\n indent: 0,\n padTo,\n }),\n )\n if (sso) {\n this.log(formatKeyValue('Org', formatOrganization(sso), {indent: 0, padTo}))\n }\n this.log(formatKeyValue('Token', tokenInfo.source, {indent: 0, padTo}))\n }\n}\n\nconst ENV_TOKEN_SOURCE = 'SANITY_AUTH_TOKEN environment variable'\n\nfunction isRejectedToken(err: unknown): boolean {\n return isHttpError(err) && (err.statusCode === 401 || err.statusCode === 403)\n}\n\nfunction formatProvider(\n provider: string,\n samlProviderId: string | undefined,\n sso: SSOProviderInfo | undefined,\n): string {\n if (provider === 'sanity-token') return 'API token'\n if (samlProviderId) return formatSamlProvider(sso)\n return getProviderName(provider)\n}\n\nfunction formatOrganization(sso: SSOProviderInfo): string {\n if (!sso.organizationSlug) return sso.organizationName\n return `${sso.organizationName} (sanity login --sso ${sso.organizationSlug})`\n}\n\nfunction formatSamlProvider(sso: SSOProviderInfo | undefined): string {\n // Provider names like \"saml\" or \"SSO\" repeat the label without adding anything\n const name = sso?.providerName.trim()\n if (!name || /^(saml|sso|saml sso)$/i.test(name)) return 'SAML SSO'\n return `SAML SSO (${name})`\n}\n"],"names":["exitCodes","getCliTokenInfo","SanityCommand","isHttpError","getProviderName","formatKeyValue","getSamlProviderId","resolveSSOProvider","getCliUser","WhoamiCommand","description","enableJsonFlag","examples","command","run","json","flags","tokenInfo","token","error","exit","RUNTIME_ERROR","user","catch","err","source","ENV_TOKEN_SOURCE","isRejectedToken","samlProviderId","provider","sso","undefined","logJson","email","id","name","tokenSource","padTo","log","indent","formatProvider","formatOrganization","statusCode","formatSamlProvider","organizationSlug","organizationName","providerName","trim","test"],"mappings":"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"}