@sanity/cli 7.15.1 → 7.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +87 -0
  2. package/dist/actions/build/shouldAutoUpdate.js +28 -5
  3. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  4. package/dist/actions/deploy/deployApp.js +4 -8
  5. package/dist/actions/deploy/deployApp.js.map +1 -1
  6. package/dist/actions/deploy/deployChecks.js +49 -31
  7. package/dist/actions/deploy/deployChecks.js.map +1 -1
  8. package/dist/actions/deploy/deployRunner.js +1 -1
  9. package/dist/actions/deploy/deployRunner.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +12 -10
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/deploy/deploymentPlan.js +2 -2
  13. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  14. package/dist/actions/deploy/resolveDeployTarget.js +13 -13
  15. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  16. package/dist/actions/init/bootstrapLocalTemplate.js +2 -3
  17. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  18. package/dist/actions/init/createAppCliConfig.js.map +1 -1
  19. package/dist/actions/init/createCliConfig.js.map +1 -1
  20. package/dist/actions/init/initNextJs.js +1 -1
  21. package/dist/actions/init/initNextJs.js.map +1 -1
  22. package/dist/actions/init/initStudio.js +10 -6
  23. package/dist/actions/init/initStudio.js.map +1 -1
  24. package/dist/actions/init/templates/appSanityUi.js +1 -1
  25. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  26. package/dist/actions/init/templates/getStarted.js +2 -2
  27. package/dist/actions/init/templates/getStarted.js.map +1 -1
  28. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js +4 -4
  29. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js.map +1 -1
  30. package/dist/actions/init/templates/shopify.js +5 -5
  31. package/dist/actions/init/templates/shopify.js.map +1 -1
  32. package/dist/actions/init/templates/shopifyOnline.js +3 -3
  33. package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
  34. package/dist/actions/manifest/extractCoreAppManifest.js +7 -7
  35. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  36. package/dist/actions/scaffold/createFrontend.js +107 -0
  37. package/dist/actions/scaffold/createFrontend.js.map +1 -0
  38. package/dist/actions/scaffold/scaffoldProject.js +202 -0
  39. package/dist/actions/scaffold/scaffoldProject.js.map +1 -0
  40. package/dist/commands/backups/list.js +1 -1
  41. package/dist/commands/backups/list.js.map +1 -1
  42. package/dist/commands/migrations/list.js +1 -1
  43. package/dist/commands/migrations/list.js.map +1 -1
  44. package/dist/commands/migrations/run.js +1 -1
  45. package/dist/commands/migrations/run.js.map +1 -1
  46. package/dist/commands/new.js +309 -0
  47. package/dist/commands/new.js.map +1 -0
  48. package/dist/commands/organizations/list.js +1 -1
  49. package/dist/commands/organizations/list.js.map +1 -1
  50. package/dist/commands/projects/unclaimed.js +205 -0
  51. package/dist/commands/projects/unclaimed.js.map +1 -0
  52. package/dist/commands/tokens/list.js +1 -1
  53. package/dist/commands/tokens/list.js.map +1 -1
  54. package/dist/commands/users/list.js +5 -1
  55. package/dist/commands/users/list.js.map +1 -1
  56. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +4 -0
  57. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  58. package/dist/exports/runtime.d.ts +24 -0
  59. package/dist/exports/runtime.js.map +1 -1
  60. package/dist/services/mintProject.js +91 -0
  61. package/dist/services/mintProject.js.map +1 -0
  62. package/dist/services/projects.js +19 -0
  63. package/dist/services/projects.js.map +1 -1
  64. package/dist/util/formatClaimDeadline.js +15 -0
  65. package/dist/util/formatClaimDeadline.js.map +1 -0
  66. package/dist/util/mintProjectConstants.js +6 -0
  67. package/dist/util/mintProjectConstants.js.map +1 -0
  68. package/dist/util/newCommandSplash.js +27 -0
  69. package/dist/util/newCommandSplash.js.map +1 -0
  70. package/dist/util/packageManager/installPackages.js +57 -28
  71. package/dist/util/packageManager/installPackages.js.map +1 -1
  72. package/dist/util/unclaimedProjects.js +105 -0
  73. package/dist/util/unclaimedProjects.js.map +1 -0
  74. package/oclif.config.js +1 -0
  75. package/oclif.manifest.json +111 -1
  76. package/package.json +6 -6
  77. package/templates/get-started/plugins/sanity-plugin-tutorial/GetStartedTutorial.tsx +1 -1
  78. package/templates/shopify/components/inputs/CollectionHidden.tsx +1 -1
  79. package/templates/shopify/components/inputs/ProductHidden.tsx +1 -1
  80. package/templates/shopify/components/inputs/ProductVariantHidden.tsx +1 -1
  81. package/templates/shopify/components/inputs/ProxyString.tsx +1 -1
  82. package/templates/shopify/components/media/ShopifyDocumentStatus.tsx +3 -1
  83. package/templates/shopify/constants.ts +3 -1
  84. package/templates/shopify/plugins/customDocumentActions/shopifyDelete.tsx +1 -1
  85. package/templates/shopify/plugins/customDocumentActions/shopifyLink.ts +1 -1
  86. package/templates/shopify/schemaTypes/documents/collection.tsx +1 -1
  87. package/templates/shopify/schemaTypes/documents/colorTheme.tsx +1 -1
  88. package/templates/shopify/schemaTypes/documents/page.ts +1 -1
  89. package/templates/shopify/schemaTypes/documents/product.tsx +1 -1
  90. package/templates/shopify/schemaTypes/documents/productVariant.tsx +1 -1
  91. package/templates/shopify/schemaTypes/objects/collection/collectionGroupType.ts +1 -1
  92. package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
  93. package/templates/shopify/schemaTypes/objects/link/linkEmailType.tsx +1 -1
  94. package/templates/shopify/schemaTypes/objects/link/linkExternalType.tsx +1 -1
  95. package/templates/shopify/schemaTypes/objects/link/linkInternalType.tsx +1 -1
  96. package/templates/shopify/schemaTypes/objects/link/linkProductType.tsx +1 -1
  97. package/templates/shopify/schemaTypes/objects/module/accordionType.ts +1 -1
  98. package/templates/shopify/schemaTypes/objects/module/callToActionType.tsx +2 -1
  99. package/templates/shopify/schemaTypes/objects/module/calloutType.ts +1 -1
  100. package/templates/shopify/schemaTypes/objects/module/collectionReferenceType.tsx +1 -1
  101. package/templates/shopify/schemaTypes/objects/module/gridType.ts +1 -1
  102. package/templates/shopify/schemaTypes/objects/module/imageFeatureType.ts +1 -1
  103. package/templates/shopify/schemaTypes/objects/module/imageFeaturesType.tsx +1 -1
  104. package/templates/shopify/schemaTypes/objects/module/instagramType.ts +1 -1
  105. package/templates/shopify/schemaTypes/objects/module/productFeaturesType.tsx +1 -1
  106. package/templates/shopify/schemaTypes/objects/module/productReferenceType.tsx +1 -1
  107. package/templates/shopify/schemaTypes/objects/shopify/collectionRuleType.tsx +1 -1
  108. package/templates/shopify/schemaTypes/objects/shopify/optionType.tsx +1 -1
  109. package/templates/shopify/schemaTypes/objects/shopify/productWithVariantType.tsx +1 -1
  110. package/templates/shopify/schemaTypes/singletons/homeType.ts +1 -1
  111. package/templates/shopify/schemaTypes/singletons/settingsType.ts +5 -1
  112. package/templates/shopify/structure/pageStructure.ts +1 -1
  113. package/templates/shopify/structure/productStructure.ts +1 -1
  114. package/templates/shopify-online-storefront/components/inputs/CollectionHidden.tsx +1 -1
  115. package/templates/shopify-online-storefront/components/inputs/ProductHidden.tsx +1 -1
  116. package/templates/shopify-online-storefront/components/inputs/ProductVariantHidden.tsx +1 -1
  117. package/templates/shopify-online-storefront/components/inputs/ProxyString.tsx +1 -1
  118. package/templates/shopify-online-storefront/components/media/ShopifyDocumentStatus.tsx +3 -1
  119. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyDelete.tsx +1 -1
  120. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyLink.ts +1 -1
  121. package/templates/shopify-online-storefront/schemaTypes/documents/collection.tsx +1 -1
  122. package/templates/shopify-online-storefront/schemaTypes/documents/product.tsx +1 -1
  123. package/templates/shopify-online-storefront/schemaTypes/documents/productVariant.tsx +1 -1
  124. package/templates/shopify-online-storefront/schemaTypes/objects/accordion.ts +1 -1
  125. package/templates/shopify-online-storefront/schemaTypes/objects/callout.ts +1 -1
  126. package/templates/shopify-online-storefront/schemaTypes/objects/option.ts +1 -1
  127. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollectionRule.tsx +1 -1
  128. package/templates/shopify-online-storefront/structure/productStructure.ts +1 -1
@@ -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'\nimport {Table} from 'console-table-printer'\n\nimport {type Token} from '../../actions/tokens/types.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for the project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output tokens in JSON format',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.tokens'}],\n }),\n })\n\n let tokens: Token[]\n try {\n tokens = await getTokens(projectId)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for project ${projectId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: 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 project.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 40, name: 'label', title: 'Label'},\n {alignment: 'left', maxLen: 20, name: 'id', title: 'Token ID'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = token.roles?.map((role) => role.title).join(', ') || 'No roles'\n const truncatedLabel =\n token.label.length > 37 ? `${token.label.slice(0, 37)}...` : token.label\n const truncatedRoles = roles.length > 27 ? `${roles.slice(0, 27)}...` : roles\n\n table.addRow({\n id: token.id,\n label: truncatedLabel,\n roles: truncatedRoles,\n })\n }\n\n table.printTable()\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","Table","promptForProject","getTokens","getProjectIdFlag","listTokenDebug","TokensListCommand","description","examples","command","flags","semantics","json","boolean","default","hiddenAliases","run","parse","outputJson","projectId","getProjectId","fallback","requiredPermissions","grant","permission","tokens","error","message","exit","RUNTIME_ERROR","log","JSON","stringify","length","table","columns","alignment","maxLen","name","title","token","roles","map","role","join","truncatedLabel","label","slice","truncatedRoles","addRow","id","printTable"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,KAAK,QAAO,wBAAuB;AAG3C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,iBAAiBN,SAAS;AAEhC,OAAO,MAAMO,0BAA0BR;IACrC,OAAgBS,cAAc,kCAAiC;IAC/D,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;QACFC,MAAMhB,MAAMiB,OAAO,CAAC;YAClBC,SAAS;YACTP,aAAa;QACf;IACF,EAAC;IAED,OAAgBQ,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACX;QACjC,MAAM,EAACM,IAAI,EAAC,GAAGF;QACf,MAAMQ,aAAaN,QAAQ;QAE3B,iCAAiC;QACjC,MAAMO,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAuB;qBAAE;gBAC7E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMtB,UAAUgB;QAC3B,EAAE,OAAOO,OAAO;YACd,MAAMC,UAAU3B,gBAAgB0B;YAChCrB,eAAe,CAAC,kCAAkC,EAAEc,WAAW,EAAEO;YACjE,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACC,MAAM/B,UAAUgC,aAAa;YAAA;QACvF;QAEA,IAAIX,YAAY;YACd,IAAI,CAACY,GAAG,CAACC,KAAKC,SAAS,CAACP,QAAQ,MAAM;YACtC;QACF;QAEA,IAAIA,OAAOQ,MAAM,KAAK,GAAG;YACvB,IAAI,CAACH,GAAG,CAAC;YACT;QACF;QAEA,MAAMI,QAAQ,IAAIjC,MAAM;YACtBkC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAAMC,OAAO;gBAAU;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;aAC9D;YACDA,OAAO,CAAC,MAAM,EAAEd,OAAOQ,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMO,SAASf,OAAQ;YAC1B,MAAMgB,QAAQD,MAAMC,KAAK,EAAEC,IAAI,CAACC,OAASA,KAAKJ,KAAK,EAAEK,KAAK,SAAS;YACnE,MAAMC,iBACJL,MAAMM,KAAK,CAACb,MAAM,GAAG,KAAK,GAAGO,MAAMM,KAAK,CAACC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGP,MAAMM,KAAK;YAC1E,MAAME,iBAAiBP,MAAMR,MAAM,GAAG,KAAK,GAAGQ,MAAMM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGN;YAExEP,MAAMe,MAAM,CAAC;gBACXC,IAAIV,MAAMU,EAAE;gBACZJ,OAAOD;gBACPJ,OAAOO;YACT;QACF;QAEAd,MAAMiB,UAAU;IAClB;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/tokens/list.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {Table} from 'console-table-printer'\n\nimport {type Token} from '../../actions/tokens/types.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getTokens} from '../../services/tokens.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listTokenDebug = subdebug('tokens:list')\n\nexport class TokensListCommand extends SanityCommand<typeof TokensListCommand> {\n static override description = 'List API tokens for the project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List tokens for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'List tokens in JSON format',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List tokens for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list tokens for',\n semantics: 'override',\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output tokens in JSON format',\n }),\n }\n\n static override hiddenAliases: string[] = ['token:list']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TokensListCommand)\n const {json} = flags\n const outputJson = json ?? false\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.tokens'}],\n }),\n })\n\n let tokens: Token[]\n try {\n tokens = await getTokens(projectId)\n } catch (error) {\n const message = getErrorMessage(error)\n listTokenDebug(`Error fetching tokens for project ${projectId}`, error)\n this.error(`Token list retrieval failed:\\n${message}`, {exit: 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 project.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 40, name: 'label', title: 'Label'},\n {alignment: 'left', maxLen: 20, name: 'id', title: 'Token ID'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n ],\n title: `Found ${tokens.length} API tokens`,\n })\n\n for (const token of tokens) {\n const roles = token.roles?.map((role) => role.title).join(', ') || 'No roles'\n const truncatedLabel =\n token.label.length > 37 ? `${token.label.slice(0, 37)}...` : token.label\n const truncatedRoles = roles.length > 27 ? `${roles.slice(0, 27)}...` : roles\n\n table.addRow({\n id: token.id,\n label: truncatedLabel,\n roles: truncatedRoles,\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","Table","promptForProject","getTokens","getProjectIdFlag","listTokenDebug","TokensListCommand","description","examples","command","flags","semantics","json","boolean","default","hiddenAliases","run","parse","outputJson","projectId","getProjectId","fallback","requiredPermissions","grant","permission","tokens","error","message","exit","RUNTIME_ERROR","log","JSON","stringify","length","table","columns","alignment","maxLen","name","title","token","roles","map","role","join","truncatedLabel","label","slice","truncatedRoles","addRow","id","render"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,KAAK,QAAO,wBAAuB;AAG3C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,iBAAiBN,SAAS;AAEhC,OAAO,MAAMO,0BAA0BR;IACrC,OAAgBS,cAAc,kCAAiC;IAC/D,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IACD,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;QACFC,MAAMhB,MAAMiB,OAAO,CAAC;YAClBC,SAAS;YACTP,aAAa;QACf;IACF,EAAC;IAED,OAAgBQ,gBAA0B;QAAC;KAAa,CAAA;IAExD,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACX;QACjC,MAAM,EAACM,IAAI,EAAC,GAAGF;QACf,MAAMQ,aAAaN,QAAQ;QAE3B,iCAAiC;QACjC,MAAMO,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAuB;qBAAE;gBAC7E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,SAAS,MAAMtB,UAAUgB;QAC3B,EAAE,OAAOO,OAAO;YACd,MAAMC,UAAU3B,gBAAgB0B;YAChCrB,eAAe,CAAC,kCAAkC,EAAEc,WAAW,EAAEO;YACjE,IAAI,CAACA,KAAK,CAAC,CAAC,8BAA8B,EAAEC,SAAS,EAAE;gBAACC,MAAM/B,UAAUgC,aAAa;YAAA;QACvF;QAEA,IAAIX,YAAY;YACd,IAAI,CAACY,GAAG,CAACC,KAAKC,SAAS,CAACP,QAAQ,MAAM;YACtC;QACF;QAEA,IAAIA,OAAOQ,MAAM,KAAK,GAAG;YACvB,IAAI,CAACH,GAAG,CAAC;YACT;QACF;QAEA,MAAMI,QAAQ,IAAIjC,MAAM;YACtBkC,SAAS;gBACP;oBAACC,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAAMC,OAAO;gBAAU;gBAC7D;oBAACH,WAAW;oBAAQC,QAAQ;oBAAIC,MAAM;oBAASC,OAAO;gBAAO;aAC9D;YACDA,OAAO,CAAC,MAAM,EAAEd,OAAOQ,MAAM,CAAC,WAAW,CAAC;QAC5C;QAEA,KAAK,MAAMO,SAASf,OAAQ;YAC1B,MAAMgB,QAAQD,MAAMC,KAAK,EAAEC,IAAI,CAACC,OAASA,KAAKJ,KAAK,EAAEK,KAAK,SAAS;YACnE,MAAMC,iBACJL,MAAMM,KAAK,CAACb,MAAM,GAAG,KAAK,GAAGO,MAAMM,KAAK,CAACC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGP,MAAMM,KAAK;YAC1E,MAAME,iBAAiBP,MAAMR,MAAM,GAAG,KAAK,GAAGQ,MAAMM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,GAAGN;YAExEP,MAAMe,MAAM,CAAC;gBACXC,IAAIV,MAAMU,EAAE;gBACZJ,OAAOD;gBACPJ,OAAOO;YACT;QACF;QAEA,IAAI,CAAClB,GAAG,CAACI,MAAMiB,MAAM;IACvB;AACF"}
@@ -93,6 +93,10 @@ export class List extends SanityCommand {
93
93
  includeRobots: robots,
94
94
  projectId
95
95
  });
96
+ if (members.length === 0) {
97
+ this.log('No members found for this project.');
98
+ return;
99
+ }
96
100
  const ordered = sortBy(members.map(({ date, id, name, roles })=>[
97
101
  id,
98
102
  name,
@@ -140,7 +144,7 @@ export class List extends SanityCommand {
140
144
  roles: dimText(roles, isPending)
141
145
  });
142
146
  }
143
- table.printTable();
147
+ this.log(table.render());
144
148
  }
145
149
  }
146
150
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/users/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {getMembersForProject} from '../../actions/users/getMembersForProject.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst sortFields = ['id', 'name', 'role', 'date']\n\nfunction dimText(value: string, isDim: boolean): string {\n return isDim ? styleText('dim', value) : value\n}\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List project members'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all users of the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-invitations --no-robots',\n description: 'List all users of the project, but exclude pending invitations and robots',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort role',\n description: 'List all users, sorted by role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List users for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list users for',\n semantics: 'override',\n }),\n invitations: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes pending invitations',\n }),\n order: Flags.string({\n default: 'asc',\n description: 'Sort output ascending/descending',\n options: ['asc', 'desc'],\n }),\n robots: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes robots (token users)',\n }),\n sort: Flags.string({\n default: 'date',\n description: 'Sort users by specified column',\n options: ['id', 'name', 'role', 'date'],\n }),\n }\n\n static override hiddenAliases: string[] = ['user:list']\n\n public async run(): Promise<void> {\n const {invitations, order, robots, sort} = this.flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project'},\n {grant: 'read', permission: 'sanity.project.members'},\n ],\n }),\n })\n\n const members = await getMembersForProject({\n includeInvitations: invitations,\n includeRobots: robots,\n projectId,\n })\n\n const ordered = sortBy(\n members.map(({date, id, name, roles}) => [\n id,\n name,\n roles\n ?.map((role) => role.title)\n .join(', ')\n .trim() || '-',\n date,\n ]),\n [sortFields.indexOf(sort)],\n )\n\n const rows = order === 'asc' ? ordered : ordered.toReversed()\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 30, name: 'id', title: 'ID'},\n {alignment: 'left', maxLen: 40, name: 'name', title: 'Name'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n {alignment: 'left', maxLen: 12, name: 'date', title: 'Date'},\n ],\n rowSeparator: true,\n })\n\n for (const [id, name, roles, date] of rows) {\n const isPending = id === '<pending>'\n table.addRow({\n date: dimText(date, isPending),\n id: dimText(id, isPending),\n name: dimText(name, isPending),\n roles: dimText(roles, isPending),\n })\n }\n\n table.printTable()\n }\n}\n"],"names":["styleText","Flags","SanityCommand","Table","sortBy","getMembersForProject","promptForProject","getProjectIdFlag","sortFields","dimText","value","isDim","List","description","examples","command","flags","semantics","invitations","boolean","allowNo","default","order","string","options","robots","sort","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","members","includeInvitations","includeRobots","ordered","map","date","id","name","roles","role","title","join","trim","indexOf","rows","toReversed","table","columns","alignment","maxLen","rowSeparator","isPending","addRow","printTable"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/users/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {getMembersForProject} from '../../actions/users/getMembersForProject.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst sortFields = ['id', 'name', 'role', 'date']\n\nfunction dimText(value: string, isDim: boolean): string {\n return isDim ? styleText('dim', value) : value\n}\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List project members'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all users of the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --no-invitations --no-robots',\n description: 'List all users of the project, but exclude pending invitations and robots',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort role',\n description: 'List all users, sorted by role',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List users for a specific project',\n },\n ]\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list users for',\n semantics: 'override',\n }),\n invitations: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes pending invitations',\n }),\n order: Flags.string({\n default: 'asc',\n description: 'Sort output ascending/descending',\n options: ['asc', 'desc'],\n }),\n robots: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Includes or excludes robots (token users)',\n }),\n sort: Flags.string({\n default: 'date',\n description: 'Sort users by specified column',\n options: ['id', 'name', 'role', 'date'],\n }),\n }\n\n static override hiddenAliases: string[] = ['user:list']\n\n public async run(): Promise<void> {\n const {invitations, order, robots, sort} = this.flags\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project'},\n {grant: 'read', permission: 'sanity.project.members'},\n ],\n }),\n })\n\n const members = await getMembersForProject({\n includeInvitations: invitations,\n includeRobots: robots,\n projectId,\n })\n\n if (members.length === 0) {\n this.log('No members found for this project.')\n return\n }\n\n const ordered = sortBy(\n members.map(({date, id, name, roles}) => [\n id,\n name,\n roles\n ?.map((role) => role.title)\n .join(', ')\n .trim() || '-',\n date,\n ]),\n [sortFields.indexOf(sort)],\n )\n\n const rows = order === 'asc' ? ordered : ordered.toReversed()\n\n const table = new Table({\n columns: [\n {alignment: 'left', maxLen: 30, name: 'id', title: 'ID'},\n {alignment: 'left', maxLen: 40, name: 'name', title: 'Name'},\n {alignment: 'left', maxLen: 30, name: 'roles', title: 'Roles'},\n {alignment: 'left', maxLen: 12, name: 'date', title: 'Date'},\n ],\n rowSeparator: true,\n })\n\n for (const [id, name, roles, date] of rows) {\n const isPending = id === '<pending>'\n table.addRow({\n date: dimText(date, isPending),\n id: dimText(id, isPending),\n name: dimText(name, isPending),\n roles: dimText(roles, isPending),\n })\n }\n\n this.log(table.render())\n }\n}\n"],"names":["styleText","Flags","SanityCommand","Table","sortBy","getMembersForProject","promptForProject","getProjectIdFlag","sortFields","dimText","value","isDim","List","description","examples","command","flags","semantics","invitations","boolean","allowNo","default","order","string","options","robots","sort","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","members","includeInvitations","includeRobots","length","log","ordered","map","date","id","name","roles","role","title","join","trim","indexOf","rows","toReversed","table","columns","alignment","maxLen","rowSeparator","isPending","addRow","render"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,QAAO,mBAAkB;AAC9C,SAAQC,KAAK,QAAO,wBAAuB;AAC3C,OAAOC,YAAY,sBAAqB;AAExC,SAAQC,oBAAoB,QAAO,8CAA6C;AAChF,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,aAAa;IAAC;IAAM;IAAQ;IAAQ;CAAO;AAEjD,SAASC,QAAQC,KAAa,EAAEC,KAAc;IAC5C,OAAOA,QAAQX,UAAU,OAAOU,SAASA;AAC3C;AAEA,OAAO,MAAME,aAAaV;IACxB,OAAgBW,cAAc,uBAAsB;IACpD,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,GAAGT,iBAAiB;YAClBM,aAAa;YACbI,WAAW;QACb,EAAE;QACFC,aAAajB,MAAMkB,OAAO,CAAC;YACzBC,SAAS;YACTC,SAAS;YACTR,aAAa;QACf;QACAS,OAAOrB,MAAMsB,MAAM,CAAC;YAClBF,SAAS;YACTR,aAAa;YACbW,SAAS;gBAAC;gBAAO;aAAO;QAC1B;QACAC,QAAQxB,MAAMkB,OAAO,CAAC;YACpBC,SAAS;YACTC,SAAS;YACTR,aAAa;QACf;QACAa,MAAMzB,MAAMsB,MAAM,CAAC;YACjBF,SAAS;YACTR,aAAa;YACbW,SAAS;gBAAC;gBAAM;gBAAQ;gBAAQ;aAAO;QACzC;IACF,EAAC;IAED,OAAgBG,gBAA0B;QAAC;KAAY,CAAA;IAEvD,MAAaC,MAAqB;QAChC,MAAM,EAACV,WAAW,EAAEI,KAAK,EAAEG,MAAM,EAAEC,IAAI,EAAC,GAAG,IAAI,CAACV,KAAK;QAErD,MAAMa,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRzB,iBAAiB;oBACf0B,qBAAqB;wBACnB;4BAACC,OAAO;4BAAQC,YAAY;wBAAgB;wBAC5C;4BAACD,OAAO;4BAAQC,YAAY;wBAAwB;qBACrD;gBACH;QACJ;QAEA,MAAMC,UAAU,MAAM9B,qBAAqB;YACzC+B,oBAAoBlB;YACpBmB,eAAeZ;YACfI;QACF;QAEA,IAAIM,QAAQG,MAAM,KAAK,GAAG;YACxB,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,MAAMC,UAAUpC,OACd+B,QAAQM,GAAG,CAAC,CAAC,EAACC,IAAI,EAAEC,EAAE,EAAEC,IAAI,EAAEC,KAAK,EAAC,GAAK;gBACvCF;gBACAC;gBACAC,OACIJ,IAAI,CAACK,OAASA,KAAKC,KAAK,EACzBC,KAAK,MACLC,UAAU;gBACbP;aACD,GACD;YAAClC,WAAW0C,OAAO,CAACxB;SAAM;QAG5B,MAAMyB,OAAO7B,UAAU,QAAQkB,UAAUA,QAAQY,UAAU;QAE3D,MAAMC,QAAQ,IAAIlD,MAAM;YACtBmD,SAAS;gBACP;oBAACC,WAAW;oBAAQC,QAAQ;oBAAIZ,MAAM;oBAAMG,OAAO;gBAAI;gBACvD;oBAACQ,WAAW;oBAAQC,QAAQ;oBAAIZ,MAAM;oBAAQG,OAAO;gBAAM;gBAC3D;oBAACQ,WAAW;oBAAQC,QAAQ;oBAAIZ,MAAM;oBAASG,OAAO;gBAAO;gBAC7D;oBAACQ,WAAW;oBAAQC,QAAQ;oBAAIZ,MAAM;oBAAQG,OAAO;gBAAM;aAC5D;YACDU,cAAc;QAChB;QAEA,KAAK,MAAM,CAACd,IAAIC,MAAMC,OAAOH,KAAK,IAAIS,KAAM;YAC1C,MAAMO,YAAYf,OAAO;YACzBU,MAAMM,MAAM,CAAC;gBACXjB,MAAMjC,QAAQiC,MAAMgB;gBACpBf,IAAIlC,QAAQkC,IAAIe;gBAChBd,MAAMnC,QAAQmC,MAAMc;gBACpBb,OAAOpC,QAAQoC,OAAOa;YACxB;QACF;QAEA,IAAI,CAACnB,GAAG,CAACc,MAAMO,MAAM;IACvB;AACF"}
@@ -127,6 +127,8 @@ import { allow, conditionalDenyFlags, conditionalPolicy, deny } from './policy.j
127
127
  'migrations:list': deny,
128
128
  // Executes local migration code that may perform arbitrary document mutations.
129
129
  'migrations:run': deny,
130
+ // Writes project setup values and scaffolds local applications.
131
+ new: deny,
130
132
  // --web opens a browser on the machine running the MCP server.
131
133
  'openapi:get': conditionalDenyFlags('web'),
132
134
  'openapi:list': conditionalDenyFlags('web'),
@@ -139,6 +141,8 @@ import { allow, conditionalDenyFlags, conditionalPolicy, deny } from './policy.j
139
141
  preview: deny,
140
142
  'projects:create': allow,
141
143
  'projects:list': allow,
144
+ // Reads locally stored claim URLs and robot tokens.
145
+ 'projects:unclaimed': deny,
142
146
  // Loads the local Studio configuration to resolve the datasets containing each schema.
143
147
  'schemas:delete': deny,
144
148
  // Loads local schema files before deploying them.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from './policy.js'\n\n/**\n * A typed `-F/--field` value of `@<file>` or `@-` makes the `api` command\n * read the host's filesystem or stdin (raw `-f` fields are always verbatim).\n */\nfunction fieldReadsFromHost(field: unknown): boolean {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n}\n\n/** A `-H/--header` value that replaces the invocation's authentication. */\nfunction headerOverridesAuthentication(header: unknown): boolean {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n return (\n separatorIndex > 0 && header.slice(0, separatorIndex).trim().toLowerCase() === 'authorization'\n )\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every manifest command must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token` and an Authorization header replace the MCP user's token,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: ({flags}) =>\n (!Array.isArray(flags.field) || !flags.field.some((field) => fieldReadsFromHost(field))) &&\n (!Array.isArray(flags.header) ||\n !flags.header.some((header) => headerOverridesAuthentication(header))),\n }),\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // Reads media assets from the local filesystem.\n 'media:import': deny,\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","fieldReadsFromHost","field","separatorIndex","indexOf","headerOverridesAuthentication","header","slice","trim","toLowerCase","mcpPolicy","api","deniedFlags","validate","flags","Array","isArray","some","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","preview","undeploy","versions"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from './policy.js'\n\n/**\n * A typed `-F/--field` value of `@<file>` or `@-` makes the `api` command\n * read the host's filesystem or stdin (raw `-f` fields are always verbatim).\n */\nfunction fieldReadsFromHost(field: unknown): boolean {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n}\n\n/** A `-H/--header` value that replaces the invocation's authentication. */\nfunction headerOverridesAuthentication(header: unknown): boolean {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n return (\n separatorIndex > 0 && header.slice(0, separatorIndex).trim().toLowerCase() === 'authorization'\n )\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every manifest command must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token` and an Authorization header replace the MCP user's token,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: ({flags}) =>\n (!Array.isArray(flags.field) || !flags.field.some((field) => fieldReadsFromHost(field))) &&\n (!Array.isArray(flags.header) ||\n !flags.header.some((header) => headerOverridesAuthentication(header))),\n }),\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // Reads media assets from the local filesystem.\n 'media:import': deny,\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // Writes project setup values and scaffolds local applications.\n new: deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n // Reads locally stored claim URLs and robot tokens.\n 'projects:unclaimed': deny,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","fieldReadsFromHost","field","separatorIndex","indexOf","headerOverridesAuthentication","header","slice","trim","toLowerCase","mcpPolicy","api","deniedFlags","validate","flags","Array","isArray","some","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","new","preview","undeploy","versions"],"mappings":"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"}
@@ -1,3 +1,7 @@
1
+ import { AssetSource } from "@sanity/types";
2
+ import { AssetSourceComponent } from "@sanity/workbench-cli";
3
+ import { AssetSourceComponentProps } from "@sanity/types";
4
+ import { AssetSourceViewComponents } from "@sanity/workbench-cli";
1
5
  import { DefinedService } from "@sanity/workbench-cli";
2
6
  import { DefinedView } from "@sanity/workbench-cli";
3
7
  import { InterfaceType } from "@sanity/workbench-cli";
@@ -8,10 +12,22 @@ import { ServiceCallback } from "@sanity/workbench-cli";
8
12
  import { ServiceContext } from "@sanity/workbench-cli";
9
13
  import { ServiceInfo } from "@sanity/workbench-cli";
10
14
  import { ServiceType } from "@sanity/workbench-cli";
15
+ import { TileComponent } from "@sanity/workbench-cli";
16
+ import { TileSize } from "@sanity/workbench-cli";
17
+ import { TileViewComponents } from "@sanity/workbench-cli";
18
+ import { TileViewProps } from "@sanity/workbench-cli";
11
19
  import { unstable_defineService } from "@sanity/workbench-cli";
12
20
  import { unstable_defineView } from "@sanity/workbench-cli";
13
21
  import { ViewComponentsByType } from "@sanity/workbench-cli";
14
22
 
23
+ export { AssetSource };
24
+
25
+ export { AssetSourceComponent };
26
+
27
+ export { AssetSourceComponentProps };
28
+
29
+ export { AssetSourceViewComponents };
30
+
15
31
  export { DefinedService };
16
32
 
17
33
  export { DefinedView };
@@ -32,6 +48,14 @@ export { ServiceInfo };
32
48
 
33
49
  export { ServiceType };
34
50
 
51
+ export { TileComponent };
52
+
53
+ export { TileSize };
54
+
55
+ export { TileViewComponents };
56
+
57
+ export { TileViewProps };
58
+
35
59
  export { unstable_defineService };
36
60
 
37
61
  export { unstable_defineView };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/runtime.ts"],"sourcesContent":["// Browser-safe runtime authoring helpers for the module-federation extension API.\n//\n// View/service src files bundle to the browser, so this entry re-exports ONLY\n// from dependency-light, browser-safe modules — it must never import\n// `@sanity/cli-core` or anything Node-only, or it would drag the CLI into the\n// frontend bundle. The `sanity` runtime package re-exports from here, so the\n// same constraint protects it.\n//\n// `unstable_defineApp` is config-time (Node) and stays on the main `@sanity/cli`\n// entry; only the runtime helpers live here.\nexport type {\n DefinedService,\n DefinedView,\n InterfaceType,\n PanelComponent,\n PanelViewComponents,\n PanelViewProps,\n ServiceCallback,\n ServiceContext,\n ServiceInfo,\n ServiceType,\n ViewComponentsByType,\n} from '@sanity/workbench-cli'\nexport {unstable_defineService, unstable_defineView} from '@sanity/workbench-cli'\n"],"names":["unstable_defineService","unstable_defineView"],"mappings":"AAAA,kFAAkF;AAClF,EAAE;AACF,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAC9E,6EAA6E;AAC7E,+BAA+B;AAC/B,EAAE;AACF,iFAAiF;AACjF,6CAA6C;AAc7C,SAAQA,sBAAsB,EAAEC,mBAAmB,QAAO,wBAAuB"}
1
+ {"version":3,"sources":["../../src/exports/runtime.ts"],"sourcesContent":["// Browser-safe runtime authoring helpers for the module-federation extension API.\n//\n// View/service src files bundle to the browser, so this entry re-exports ONLY\n// from dependency-light, browser-safe modules — it must never import\n// `@sanity/cli-core` or anything Node-only, or it would drag the CLI into the\n// frontend bundle. The `sanity` runtime package re-exports from here, so the\n// same constraint protects it.\n//\n// `unstable_defineApp` is config-time (Node) and stays on the main `@sanity/cli`\n// entry; only the runtime helpers live here.\nexport type {AssetSource, AssetSourceComponentProps} from '@sanity/types'\nexport type {\n AssetSourceComponent,\n AssetSourceViewComponents,\n DefinedService,\n DefinedView,\n InterfaceType,\n PanelComponent,\n PanelViewComponents,\n PanelViewProps,\n ServiceCallback,\n ServiceContext,\n ServiceInfo,\n ServiceType,\n TileComponent,\n TileSize,\n TileViewComponents,\n TileViewProps,\n ViewComponentsByType,\n} from '@sanity/workbench-cli'\nexport {unstable_defineService, unstable_defineView} from '@sanity/workbench-cli'\n"],"names":["unstable_defineService","unstable_defineView"],"mappings":"AAAA,kFAAkF;AAClF,EAAE;AACF,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAC9E,6EAA6E;AAC7E,+BAA+B;AAC/B,EAAE;AACF,iFAAiF;AACjF,6CAA6C;AAqB7C,SAAQA,sBAAsB,EAAEC,mBAAmB,QAAO,wBAAuB"}
@@ -0,0 +1,91 @@
1
+ import { subdebug } from '@sanity/cli-core/debug';
2
+ import { createRequester } from '@sanity/cli-core/request';
3
+ import { isStaging } from '@sanity/cli-core/util';
4
+ import { TERMS_OF_SERVICE_FALLBACK_NOTICE, TERMS_OF_SERVICE_FALLBACK_URL } from '../util/mintProjectConstants.js';
5
+ const debug = subdebug('new:provision');
6
+ /** Provision API version for minting unclaimed projects. */ export const PROVISION_API_VERSION = 'v2026-06-23';
7
+ const request = createRequester({
8
+ middleware: {
9
+ httpErrors: false,
10
+ promise: {
11
+ onlyBody: false
12
+ }
13
+ }
14
+ });
15
+ function getProvisionApiBase() {
16
+ const override = process.env.SANITY_API_HOST;
17
+ if (override) return override.replace(/\/$/u, '');
18
+ return isStaging() ? 'https://api.sanity.work' : 'https://api.sanity.io';
19
+ }
20
+ function parseJsonBody(body) {
21
+ if (typeof body !== 'string') return body;
22
+ try {
23
+ return JSON.parse(body);
24
+ } catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ function getString(value) {
29
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
30
+ }
31
+ function parseProvisionResponse(body) {
32
+ const data = parseJsonBody(body);
33
+ const response = data && typeof data === 'object' && !Array.isArray(data) ? data : {};
34
+ const links = response.links && typeof response.links === 'object' && !Array.isArray(response.links) ? response.links : {};
35
+ const terms = response.terms && typeof response.terms === 'object' && !Array.isArray(response.terms) ? response.terms : {};
36
+ const minted = {
37
+ apiHost: getString(response.apiHost),
38
+ claimApiUrl: getString(links.claimApiUrl),
39
+ claimToken: getString(response.claimToken),
40
+ claimUrl: getString(links.claimUrl),
41
+ datasetName: getString(response.datasetName),
42
+ expiresAt: getString(response.expiresAt),
43
+ resourceId: getString(response.resourceId),
44
+ token: getString(response.token)
45
+ };
46
+ const missing = Object.entries(minted).filter(([, value])=>value === undefined).map(([key])=>key);
47
+ if (response.resourceType !== 'project') {
48
+ missing.push('resourceType');
49
+ }
50
+ if (missing.length > 0) {
51
+ throw new Error(`Project creation response is missing or invalid: ${missing.join(', ')}`);
52
+ }
53
+ return {
54
+ ...minted,
55
+ termsNotice: getString(terms.notice) ?? TERMS_OF_SERVICE_FALLBACK_NOTICE,
56
+ termsUrl: getString(terms.url) ?? TERMS_OF_SERVICE_FALLBACK_URL
57
+ };
58
+ }
59
+ /**
60
+ * Mint an unclaimed Sanity project through the public provision endpoint.
61
+ */ export async function mintUnclaimedProject(options) {
62
+ const displayName = options.displayName.trim();
63
+ if (!displayName || displayName.length > 80) {
64
+ throw new Error('Project name must be 1-80 characters.');
65
+ }
66
+ const url = `${getProvisionApiBase()}/${PROVISION_API_VERSION}/provision`;
67
+ debug('minting unclaimed project at %s', url);
68
+ const response = await request({
69
+ body: JSON.stringify({
70
+ displayName,
71
+ resourceType: 'project'
72
+ }),
73
+ headers: {
74
+ 'Content-Type': 'application/json'
75
+ },
76
+ method: 'POST',
77
+ url
78
+ });
79
+ if (response.statusCode === 404) {
80
+ throw new Error('Creating projects without an account is currently unavailable. Try again later, or run `sanity login` and `sanity init`.');
81
+ }
82
+ if (response.statusCode === 429) {
83
+ throw new Error('Project creation rate limit reached for this machine. Try again later.');
84
+ }
85
+ if (response.statusCode < 200 || response.statusCode >= 300) {
86
+ throw new Error(`Project creation failed (HTTP ${response.statusCode}). Try again later.`);
87
+ }
88
+ return parseProvisionResponse(response.body);
89
+ }
90
+
91
+ //# sourceMappingURL=mintProject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/services/mintProject.ts"],"sourcesContent":["import {subdebug} from '@sanity/cli-core/debug'\nimport {createRequester} from '@sanity/cli-core/request'\nimport {isStaging} from '@sanity/cli-core/util'\n\nimport {\n TERMS_OF_SERVICE_FALLBACK_NOTICE,\n TERMS_OF_SERVICE_FALLBACK_URL,\n} from '../util/mintProjectConstants.js'\n\nconst debug = subdebug('new:provision')\n\n/** Provision API version for minting unclaimed projects. */\nexport const PROVISION_API_VERSION = 'v2026-06-23'\n\nconst request = createRequester({middleware: {httpErrors: false, promise: {onlyBody: false}}})\n\nexport interface MintedProject {\n apiHost: string\n claimApiUrl: string\n claimToken: string\n claimUrl: string\n datasetName: string\n expiresAt: string\n resourceId: string\n /** Terms of Service accepted by using the project. Falls back to the bundled constants. */\n termsNotice: string\n termsUrl: string\n token: string\n}\n\nfunction getProvisionApiBase(): string {\n const override = process.env.SANITY_API_HOST\n if (override) return override.replace(/\\/$/u, '')\n return isStaging() ? 'https://api.sanity.work' : 'https://api.sanity.io'\n}\n\nfunction parseJsonBody(body: unknown): unknown {\n if (typeof body !== 'string') return body\n\n try {\n return JSON.parse(body)\n } catch {\n return undefined\n }\n}\n\nfunction getString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction parseProvisionResponse(body: unknown): MintedProject {\n const data = parseJsonBody(body)\n const response =\n data && typeof data === 'object' && !Array.isArray(data)\n ? (data as Record<string, unknown>)\n : {}\n const links =\n response.links && typeof response.links === 'object' && !Array.isArray(response.links)\n ? (response.links as Record<string, unknown>)\n : {}\n const terms =\n response.terms && typeof response.terms === 'object' && !Array.isArray(response.terms)\n ? (response.terms as Record<string, unknown>)\n : {}\n\n const minted = {\n apiHost: getString(response.apiHost),\n claimApiUrl: getString(links.claimApiUrl),\n claimToken: getString(response.claimToken),\n claimUrl: getString(links.claimUrl),\n datasetName: getString(response.datasetName),\n expiresAt: getString(response.expiresAt),\n resourceId: getString(response.resourceId),\n token: getString(response.token),\n }\n const missing = Object.entries(minted)\n .filter(([, value]) => value === undefined)\n .map(([key]) => key)\n\n if (response.resourceType !== 'project') {\n missing.push('resourceType')\n }\n if (missing.length > 0) {\n throw new Error(`Project creation response is missing or invalid: ${missing.join(', ')}`)\n }\n\n return {\n ...(minted as Omit<MintedProject, 'termsNotice' | 'termsUrl'>),\n termsNotice: getString(terms.notice) ?? TERMS_OF_SERVICE_FALLBACK_NOTICE,\n termsUrl: getString(terms.url) ?? TERMS_OF_SERVICE_FALLBACK_URL,\n }\n}\n\n/**\n * Mint an unclaimed Sanity project through the public provision endpoint.\n */\nexport async function mintUnclaimedProject(options: {displayName: string}): Promise<MintedProject> {\n const displayName = options.displayName.trim()\n if (!displayName || displayName.length > 80) {\n throw new Error('Project name must be 1-80 characters.')\n }\n\n const url = `${getProvisionApiBase()}/${PROVISION_API_VERSION}/provision`\n debug('minting unclaimed project at %s', url)\n\n const response = await request({\n body: JSON.stringify({displayName, resourceType: 'project'}),\n headers: {'Content-Type': 'application/json'},\n method: 'POST',\n url,\n })\n\n if (response.statusCode === 404) {\n throw new Error(\n 'Creating projects without an account is currently unavailable. Try again later, or run `sanity login` and `sanity init`.',\n )\n }\n if (response.statusCode === 429) {\n throw new Error('Project creation rate limit reached for this machine. Try again later.')\n }\n if (response.statusCode < 200 || response.statusCode >= 300) {\n throw new Error(`Project creation failed (HTTP ${response.statusCode}). Try again later.`)\n }\n\n return parseProvisionResponse(response.body)\n}\n"],"names":["subdebug","createRequester","isStaging","TERMS_OF_SERVICE_FALLBACK_NOTICE","TERMS_OF_SERVICE_FALLBACK_URL","debug","PROVISION_API_VERSION","request","middleware","httpErrors","promise","onlyBody","getProvisionApiBase","override","process","env","SANITY_API_HOST","replace","parseJsonBody","body","JSON","parse","undefined","getString","value","length","parseProvisionResponse","data","response","Array","isArray","links","terms","minted","apiHost","claimApiUrl","claimToken","claimUrl","datasetName","expiresAt","resourceId","token","missing","Object","entries","filter","map","key","resourceType","push","Error","join","termsNotice","notice","termsUrl","url","mintUnclaimedProject","options","displayName","trim","stringify","headers","method","statusCode"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { debug, getGlobalCliClient, getProjectCliClient } from '@sanity/cli-core';
2
2
  export const PROJECTS_API_VERSION = '2025-09-22';
3
3
  export const CREATE_PROJECT_API_VERSION = 'v2025-05-14';
4
+ const UNCLAIMED_PROJECT_ORGANIZATION_ID = 'oSystemUnclaimed';
4
5
  /**
5
6
  * Create a new Sanity project
6
7
  */ export async function createProject(options) {
@@ -37,6 +38,24 @@ export async function getProjectById(projectId) {
37
38
  });
38
39
  return client.projects.getById(projectId);
39
40
  }
41
+ export async function getProjectClaimStatus(projectId, token) {
42
+ try {
43
+ const client = await getProjectCliClient({
44
+ apiVersion: PROJECTS_API_VERSION,
45
+ projectId,
46
+ requireUser: true,
47
+ token
48
+ });
49
+ const project = await client.projects.getById(projectId);
50
+ if (typeof project.organizationId !== 'string' || project.organizationId.length === 0) {
51
+ return 'unknown';
52
+ }
53
+ return project.organizationId === UNCLAIMED_PROJECT_ORGANIZATION_ID ? 'unclaimed' : 'claimed';
54
+ } catch (error) {
55
+ debug('failed to check claim status for project %s: %s', projectId, error instanceof Error ? error.message : `${error}`);
56
+ return 'unknown';
57
+ }
58
+ }
40
59
  export async function getProjectRoles(projectId) {
41
60
  const client = await getGlobalCliClient({
42
61
  apiVersion: PROJECTS_API_VERSION,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/projects.ts"],"sourcesContent":["import {debug, getGlobalCliClient, getProjectCliClient} from '@sanity/cli-core'\nimport {SanityProject} from '@sanity/client'\n\nimport {type Invite, type Role} from '../actions/users/types.js'\n\nexport const PROJECTS_API_VERSION = '2025-09-22'\n\nexport const CREATE_PROJECT_API_VERSION = 'v2025-05-14'\n\ninterface CreateProjectOptions {\n displayName: string\n\n metadata?: {\n coupon?: string\n integration?: string\n }\n organizationId?: string\n subscription?: {planId: string}\n}\n\nexport interface CreateProjectResult {\n displayName: string\n projectId: string\n}\n\n/**\n * Create a new Sanity project\n */\nexport async function createProject(options: CreateProjectOptions): Promise<CreateProjectResult> {\n const client = await getGlobalCliClient({\n apiVersion: CREATE_PROJECT_API_VERSION,\n requireUser: true,\n })\n\n try {\n const response = await client.request({\n body: {\n ...options,\n metadata: {\n ...options?.metadata,\n integration: 'cli',\n },\n },\n method: 'POST',\n uri: '/projects',\n })\n\n return {\n displayName: options.displayName || '',\n projectId: response.projectId || response.id,\n }\n } catch (err) {\n debug('Error creating project', err)\n throw err\n }\n}\n\nexport async function getProjectById(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n return client.projects.getById(projectId)\n}\n\nexport async function getProjectRoles(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Role[]>({uri: `/projects/${projectId}/roles`})\n}\n\ninterface InviteUserOptions {\n email: string\n projectId: string\n role: string\n}\n\nexport async function inviteUser({email, projectId, role}: InviteUserOptions) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request({\n body: {email, role},\n maxRedirects: 0,\n method: 'POST',\n uri: `/invitations/project/${projectId}`,\n useGlobalApi: true,\n })\n}\n\nexport async function listProjects({\n onlyExplicitMembership = true,\n}: {\n onlyExplicitMembership?: boolean\n} = {}) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.projects.list({onlyExplicitMembership})\n}\n\nexport async function getProjectInvites(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Invite[]>({uri: `/invitations/project/${projectId}`})\n}\n\nexport async function updateProjectInitializedAt(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n const project = await client.request<SanityProject>({uri: `/projects/${projectId}`})\n\n if (!project?.metadata?.cliInitializedAt) {\n await client.request({\n body: {metadata: {cliInitializedAt: new Date().toISOString()}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n }\n}\n\nexport async function updateProjectInitalTemplate(projectId: string, templateName: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n await client.request({\n body: {metadata: {initialTemplate: templateName}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n}\n"],"names":["debug","getGlobalCliClient","getProjectCliClient","PROJECTS_API_VERSION","CREATE_PROJECT_API_VERSION","createProject","options","client","apiVersion","requireUser","response","request","body","metadata","integration","method","uri","displayName","projectId","id","err","getProjectById","projects","getById","getProjectRoles","inviteUser","email","role","maxRedirects","useGlobalApi","listProjects","onlyExplicitMembership","list","getProjectInvites","updateProjectInitializedAt","project","cliInitializedAt","Date","toISOString","updateProjectInitalTemplate","templateName","initialTemplate"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/projects.ts"],"sourcesContent":["import {debug, getGlobalCliClient, getProjectCliClient} from '@sanity/cli-core'\nimport {SanityProject} from '@sanity/client'\n\nimport {type Invite, type Role} from '../actions/users/types.js'\n\nexport const PROJECTS_API_VERSION = '2025-09-22'\n\nexport const CREATE_PROJECT_API_VERSION = 'v2025-05-14'\n\nconst UNCLAIMED_PROJECT_ORGANIZATION_ID = 'oSystemUnclaimed'\n\nexport type ProjectClaimStatus = 'claimed' | 'unclaimed' | 'unknown'\n\ninterface CreateProjectOptions {\n displayName: string\n\n metadata?: {\n coupon?: string\n integration?: string\n }\n organizationId?: string\n subscription?: {planId: string}\n}\n\nexport interface CreateProjectResult {\n displayName: string\n projectId: string\n}\n\n/**\n * Create a new Sanity project\n */\nexport async function createProject(options: CreateProjectOptions): Promise<CreateProjectResult> {\n const client = await getGlobalCliClient({\n apiVersion: CREATE_PROJECT_API_VERSION,\n requireUser: true,\n })\n\n try {\n const response = await client.request({\n body: {\n ...options,\n metadata: {\n ...options?.metadata,\n integration: 'cli',\n },\n },\n method: 'POST',\n uri: '/projects',\n })\n\n return {\n displayName: options.displayName || '',\n projectId: response.projectId || response.id,\n }\n } catch (err) {\n debug('Error creating project', err)\n throw err\n }\n}\n\nexport async function getProjectById(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n return client.projects.getById(projectId)\n}\n\nexport async function getProjectClaimStatus(\n projectId: string,\n token: string,\n): Promise<ProjectClaimStatus> {\n try {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n token,\n })\n const project = await client.projects.getById(projectId)\n\n if (typeof project.organizationId !== 'string' || project.organizationId.length === 0) {\n return 'unknown'\n }\n\n return project.organizationId === UNCLAIMED_PROJECT_ORGANIZATION_ID ? 'unclaimed' : 'claimed'\n } catch (error) {\n debug(\n 'failed to check claim status for project %s: %s',\n projectId,\n error instanceof Error ? error.message : `${error}`,\n )\n return 'unknown'\n }\n}\n\nexport async function getProjectRoles(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Role[]>({uri: `/projects/${projectId}/roles`})\n}\n\ninterface InviteUserOptions {\n email: string\n projectId: string\n role: string\n}\n\nexport async function inviteUser({email, projectId, role}: InviteUserOptions) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request({\n body: {email, role},\n maxRedirects: 0,\n method: 'POST',\n uri: `/invitations/project/${projectId}`,\n useGlobalApi: true,\n })\n}\n\nexport async function listProjects({\n onlyExplicitMembership = true,\n}: {\n onlyExplicitMembership?: boolean\n} = {}) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.projects.list({onlyExplicitMembership})\n}\n\nexport async function getProjectInvites(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Invite[]>({uri: `/invitations/project/${projectId}`})\n}\n\nexport async function updateProjectInitializedAt(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n const project = await client.request<SanityProject>({uri: `/projects/${projectId}`})\n\n if (!project?.metadata?.cliInitializedAt) {\n await client.request({\n body: {metadata: {cliInitializedAt: new Date().toISOString()}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n }\n}\n\nexport async function updateProjectInitalTemplate(projectId: string, templateName: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n await client.request({\n body: {metadata: {initialTemplate: templateName}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n}\n"],"names":["debug","getGlobalCliClient","getProjectCliClient","PROJECTS_API_VERSION","CREATE_PROJECT_API_VERSION","UNCLAIMED_PROJECT_ORGANIZATION_ID","createProject","options","client","apiVersion","requireUser","response","request","body","metadata","integration","method","uri","displayName","projectId","id","err","getProjectById","projects","getById","getProjectClaimStatus","token","project","organizationId","length","error","Error","message","getProjectRoles","inviteUser","email","role","maxRedirects","useGlobalApi","listProjects","onlyExplicitMembership","list","getProjectInvites","updateProjectInitializedAt","cliInitializedAt","Date","toISOString","updateProjectInitalTemplate","templateName","initialTemplate"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export function formatClaimDeadline(expiresAt) {
2
+ const deadline = new Date(expiresAt);
3
+ if (!Number.isFinite(deadline.getTime())) return expiresAt;
4
+ return new Intl.DateTimeFormat('en-GB', {
5
+ day: 'numeric',
6
+ hour: '2-digit',
7
+ hour12: false,
8
+ minute: '2-digit',
9
+ month: 'long',
10
+ timeZone: 'UTC',
11
+ year: 'numeric'
12
+ }).format(deadline).replace(' at ', ', ') + ' UTC';
13
+ }
14
+
15
+ //# sourceMappingURL=formatClaimDeadline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/formatClaimDeadline.ts"],"sourcesContent":["export function formatClaimDeadline(expiresAt: string): string {\n const deadline = new Date(expiresAt)\n if (!Number.isFinite(deadline.getTime())) return expiresAt\n return (\n new Intl.DateTimeFormat('en-GB', {\n day: 'numeric',\n hour: '2-digit',\n hour12: false,\n minute: '2-digit',\n month: 'long',\n timeZone: 'UTC',\n year: 'numeric',\n })\n .format(deadline)\n .replace(' at ', ', ') + ' UTC'\n )\n}\n"],"names":["formatClaimDeadline","expiresAt","deadline","Date","Number","isFinite","getTime","Intl","DateTimeFormat","day","hour","hour12","minute","month","timeZone","year","format","replace"],"mappings":"AAAA,OAAO,SAASA,oBAAoBC,SAAiB;IACnD,MAAMC,WAAW,IAAIC,KAAKF;IAC1B,IAAI,CAACG,OAAOC,QAAQ,CAACH,SAASI,OAAO,KAAK,OAAOL;IACjD,OACE,IAAIM,KAAKC,cAAc,CAAC,SAAS;QAC/BC,KAAK;QACLC,MAAM;QACNC,QAAQ;QACRC,QAAQ;QACRC,OAAO;QACPC,UAAU;QACVC,MAAM;IACR,GACGC,MAAM,CAACd,UACPe,OAAO,CAAC,QAAQ,QAAQ;AAE/B"}
@@ -0,0 +1,6 @@
1
+ /** Product window in which an unclaimed project must be claimed. */ export const CLAIM_WINDOW_HOURS = 72;
2
+ export const SANITY_NEW_URL = 'https://sanity.new';
3
+ export const TERMS_OF_SERVICE_FALLBACK_URL = 'https://www.sanity.io/legal/tos';
4
+ export const TERMS_OF_SERVICE_FALLBACK_NOTICE = 'By continuing to use this project you accept the Sanity Terms of Service.';
5
+
6
+ //# sourceMappingURL=mintProjectConstants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/mintProjectConstants.ts"],"sourcesContent":["/** Product window in which an unclaimed project must be claimed. */\nexport const CLAIM_WINDOW_HOURS = 72\n\nexport const SANITY_NEW_URL = 'https://sanity.new'\n\nexport const TERMS_OF_SERVICE_FALLBACK_URL = 'https://www.sanity.io/legal/tos'\n\nexport const TERMS_OF_SERVICE_FALLBACK_NOTICE =\n 'By continuing to use this project you accept the Sanity Terms of Service.'\n"],"names":["CLAIM_WINDOW_HOURS","SANITY_NEW_URL","TERMS_OF_SERVICE_FALLBACK_URL","TERMS_OF_SERVICE_FALLBACK_NOTICE"],"mappings":"AAAA,kEAAkE,GAClE,OAAO,MAAMA,qBAAqB,GAAE;AAEpC,OAAO,MAAMC,iBAAiB,qBAAoB;AAElD,OAAO,MAAMC,gCAAgC,kCAAiC;AAE9E,OAAO,MAAMC,mCACX,4EAA2E"}
@@ -0,0 +1,27 @@
1
+ import { styleText } from 'node:util';
2
+ const ART = [
3
+ ' - #: @@@@',
4
+ ' @@@ @@@@@ -@@@= @@@',
5
+ ' @@@@ %@@@@@@. @@@@ %@@@@@@',
6
+ ' @@@% @@@@@@@# %@@@@@@@@@-',
7
+ ' @@@@@@@@@@@@@ @@@@@@@@.',
8
+ ' @@@@@@@= @@@# @@@@@@@ @@@@@',
9
+ ' @@@@ @@@@ @@@@@@ @@@@@@@',
10
+ ' @@@@ @@@@@@@@ @@@@@@@@',
11
+ ' +@@@@@@@@@@@@@ @@@@@@@@@@',
12
+ ' @@@@@@@@ @@@@ @@@@@@ @@@@',
13
+ ' @@@@@% *@@@% .@@@@@% .@@@@ .@@@@',
14
+ ' .- @@@@ .@@@@@% #@@@.@@@@@@@@',
15
+ ' *@@@@@@@@@% @@@@@@@@#@@@@',
16
+ ' @@@@@@@@ #@@@@@@# @@@@',
17
+ ' @@@@@@@ @@@@# @@@@',
18
+ ' #@@@@ * @@@+',
19
+ ' ='
20
+ ];
21
+ export function renderNewCommandSplash(log) {
22
+ log('');
23
+ for (const line of ART)log(styleText('cyan', line));
24
+ log('');
25
+ }
26
+
27
+ //# sourceMappingURL=newCommandSplash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/newCommandSplash.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\ntype LogFn = (message?: string) => void\n\nconst ART = [\n ' - #: @@@@',\n ' @@@ @@@@@ -@@@= @@@',\n ' @@@@ %@@@@@@. @@@@ %@@@@@@',\n ' @@@% @@@@@@@# %@@@@@@@@@-',\n ' @@@@@@@@@@@@@ @@@@@@@@.',\n ' @@@@@@@= @@@# @@@@@@@ @@@@@',\n ' @@@@ @@@@ @@@@@@ @@@@@@@',\n ' @@@@ @@@@@@@@ @@@@@@@@',\n ' +@@@@@@@@@@@@@ @@@@@@@@@@',\n ' @@@@@@@@ @@@@ @@@@@@ @@@@',\n ' @@@@@% *@@@% .@@@@@% .@@@@ .@@@@',\n ' .- @@@@ .@@@@@% #@@@.@@@@@@@@',\n ' *@@@@@@@@@% @@@@@@@@#@@@@',\n ' @@@@@@@@ #@@@@@@# @@@@',\n ' @@@@@@@ @@@@# @@@@',\n ' #@@@@ * @@@+',\n ' =',\n]\n\nexport function renderNewCommandSplash(log: LogFn): void {\n log('')\n for (const line of ART) log(styleText('cyan', line))\n log('')\n}\n"],"names":["styleText","ART","renderNewCommandSplash","log","line"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAInC,MAAMC,MAAM;IACV;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,SAASC,uBAAuBC,GAAU;IAC/CA,IAAI;IACJ,KAAK,MAAMC,QAAQH,IAAKE,IAAIH,UAAU,QAAQI;IAC9CD,IAAI;AACN"}
@@ -1,3 +1,5 @@
1
+ import { CLIError } from '@oclif/core/errors';
2
+ import { exitCodes } from '@sanity/cli-core';
1
3
  import { spinner } from '@sanity/cli-core/ux';
2
4
  import { execa } from 'execa';
3
5
  import { getPartialEnvWithNpmPath } from './packageManagerChoice.js';
@@ -58,34 +60,59 @@ function isEsbuild(ignoredEntry) {
58
60
  return ignoredEntry.replace(/@[^@]+$/, '') === 'esbuild';
59
61
  }
60
62
  async function executePackageManagerCommand(packageManager, args, execOptions, output, errorMessage) {
61
- const progress = spinner(`Running ${packageManager} ${args.join(' ')}\n`).start();
62
- const result = await execa(packageManager, args, execOptions);
63
- if (result?.exitCode || result?.failed) {
64
- // pnpm exits non-zero if dependency build scripts were skipped, even though
65
- // the install itself succeeded. Treat it as a success, but point to
66
- // `pnpm approve-builds` if anything other than esbuild was skipped
67
- // (esbuild works without its build script through a JS fallback).
68
- const commandOutput = [
69
- result.stdout,
70
- result.stderr
71
- ].filter((chunk)=>typeof chunk === 'string').join('\n');
72
- const ignoredBuilds = packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined;
73
- if (ignoredBuilds) {
74
- progress.succeed();
75
- if (ignoredBuilds.some((entry)=>!isEsbuild(entry))) {
76
- output.warn(IGNORED_BUILDS_NOTICE);
77
- }
78
- return;
79
- }
63
+ const progress = spinner({
64
+ discardStdin: !execOptions.cancelSignal,
65
+ text: `Running ${packageManager} ${args.join(' ')}\n`
66
+ }).start();
67
+ let progressSettled = false;
68
+ const fail = ()=>{
69
+ progressSettled = true;
80
70
  progress.fail();
81
- // Log both streams - package managers often print the actionable error
82
- // details to stderr, so logging stdout alone can hide the failure reason.
83
- output.log(commandOutput);
84
- output.error(errorMessage, {
85
- exit: 1
86
- });
87
- } else {
71
+ };
72
+ const succeed = ()=>{
73
+ progressSettled = true;
88
74
  progress.succeed();
75
+ };
76
+ try {
77
+ const result = await execa(packageManager, args, execOptions);
78
+ if (execOptions.cancelSignal?.aborted) {
79
+ fail();
80
+ execOptions.cancelSignal.throwIfAborted();
81
+ }
82
+ if (result?.exitCode || result?.failed) {
83
+ // pnpm exits non-zero if dependency build scripts were skipped, even though
84
+ // the install itself succeeded. Treat it as a success, but point to
85
+ // `pnpm approve-builds` if anything other than esbuild was skipped
86
+ // (esbuild works without its build script through a JS fallback).
87
+ const commandOutput = [
88
+ result.stdout,
89
+ result.stderr
90
+ ].filter((chunk)=>typeof chunk === 'string').join('\n');
91
+ const ignoredBuilds = packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined;
92
+ if (ignoredBuilds) {
93
+ succeed();
94
+ if (ignoredBuilds.some((entry)=>!isEsbuild(entry))) {
95
+ output.warn(IGNORED_BUILDS_NOTICE);
96
+ }
97
+ return;
98
+ }
99
+ fail();
100
+ // Log both streams - package managers often print the actionable error
101
+ // details to stderr, so logging stdout alone can hide the failure reason.
102
+ output.log(commandOutput);
103
+ throw new CLIError(errorMessage, {
104
+ exit: exitCodes.RUNTIME_ERROR
105
+ });
106
+ } else {
107
+ succeed();
108
+ }
109
+ } catch (err) {
110
+ if (!progressSettled) {
111
+ fail();
112
+ }
113
+ throw err;
114
+ } finally{
115
+ progress.stop();
89
116
  }
90
117
  }
91
118
  export async function installDeclaredPackages(cwd, packageManager, context) {
@@ -107,13 +134,15 @@ export async function installDeclaredPackages(cwd, packageManager, context) {
107
134
  }
108
135
  export async function installNewPackages(options, context) {
109
136
  const { packageManager, packages } = options;
110
- const { output, workDir } = context;
137
+ const { cancelSignal, output, timeout, workDir } = context;
111
138
  const execOptions = {
139
+ cancelSignal,
112
140
  cwd: workDir,
113
141
  encoding: 'utf8',
114
142
  env: getPartialEnvWithNpmPath(workDir),
115
143
  reject: false,
116
- stdio: 'pipe'
144
+ stdio: 'pipe',
145
+ timeout
117
146
  };
118
147
  if (packageManager === 'manual') {
119
148
  const npmCommand = PACKAGE_MANAGER_COMMANDS.add.npm(packages);