@sanity/cli 6.3.1 → 6.4.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 (193) hide show
  1. package/README.md +311 -452
  2. package/dist/actions/build/decorateIndexWithStagingScript.js +16 -0
  3. package/dist/actions/build/decorateIndexWithStagingScript.js.map +1 -0
  4. package/dist/actions/build/writeSanityRuntime.js +3 -2
  5. package/dist/actions/build/writeSanityRuntime.js.map +1 -1
  6. package/dist/actions/dataset/create.js +4 -0
  7. package/dist/actions/dataset/create.js.map +1 -1
  8. package/dist/actions/deploy/findUserApplicationForApp.js +1 -0
  9. package/dist/actions/deploy/findUserApplicationForApp.js.map +1 -1
  10. package/dist/actions/deploy/types.js +1 -1
  11. package/dist/actions/deploy/types.js.map +1 -1
  12. package/dist/actions/init/bootstrapLocalTemplate.js +16 -1
  13. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  14. package/dist/actions/init/initApp.js +72 -0
  15. package/dist/actions/init/initApp.js.map +1 -0
  16. package/dist/actions/init/initHelpers.js +37 -0
  17. package/dist/actions/init/initHelpers.js.map +1 -0
  18. package/dist/actions/init/initNextJs.js +246 -0
  19. package/dist/actions/init/initNextJs.js.map +1 -0
  20. package/dist/actions/init/initStudio.js +127 -0
  21. package/dist/actions/init/initStudio.js.map +1 -0
  22. package/dist/actions/init/scaffoldTemplate.js +114 -0
  23. package/dist/actions/init/scaffoldTemplate.js.map +1 -0
  24. package/dist/actions/init/templates/appQuickstart.js +2 -1
  25. package/dist/actions/init/templates/appQuickstart.js.map +1 -1
  26. package/dist/actions/init/templates/appSanityUi.js +2 -1
  27. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  28. package/dist/actions/init/templates/nextjs/index.js +1 -2
  29. package/dist/actions/init/templates/nextjs/index.js.map +1 -1
  30. package/dist/actions/init/templates/shopify.js +6 -6
  31. package/dist/actions/init/templates/shopify.js.map +1 -1
  32. package/dist/actions/init/templates/shopifyOnline.js +2 -2
  33. package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
  34. package/dist/actions/manifest/types.js +1 -1
  35. package/dist/actions/manifest/types.js.map +1 -1
  36. package/dist/actions/mcp/detectAvailableEditors.js +16 -3
  37. package/dist/actions/mcp/detectAvailableEditors.js.map +1 -1
  38. package/dist/actions/mcp/editorConfigs.js +192 -132
  39. package/dist/actions/mcp/editorConfigs.js.map +1 -1
  40. package/dist/actions/mcp/setupMCP.js +4 -1
  41. package/dist/actions/mcp/setupMCP.js.map +1 -1
  42. package/dist/actions/mcp/writeMCPConfig.js +2 -2
  43. package/dist/actions/mcp/writeMCPConfig.js.map +1 -1
  44. package/dist/actions/schema/extractSchema.js +5 -7
  45. package/dist/actions/schema/extractSchema.js.map +1 -1
  46. package/dist/actions/schema/types.js +3 -3
  47. package/dist/actions/schema/types.js.map +1 -1
  48. package/dist/actions/users/validateEmail.js +2 -2
  49. package/dist/actions/users/validateEmail.js.map +1 -1
  50. package/dist/commands/backups/disable.js +1 -1
  51. package/dist/commands/backups/disable.js.map +1 -1
  52. package/dist/commands/backups/download.js +1 -1
  53. package/dist/commands/backups/download.js.map +1 -1
  54. package/dist/commands/backups/enable.js +1 -1
  55. package/dist/commands/backups/enable.js.map +1 -1
  56. package/dist/commands/backups/list.js +1 -1
  57. package/dist/commands/backups/list.js.map +1 -1
  58. package/dist/commands/build.js +1 -1
  59. package/dist/commands/build.js.map +1 -1
  60. package/dist/commands/cors/add.js +1 -1
  61. package/dist/commands/cors/add.js.map +1 -1
  62. package/dist/commands/cors/delete.js +1 -1
  63. package/dist/commands/cors/delete.js.map +1 -1
  64. package/dist/commands/cors/list.js +2 -2
  65. package/dist/commands/cors/list.js.map +1 -1
  66. package/dist/commands/datasets/alias/create.js +1 -1
  67. package/dist/commands/datasets/alias/create.js.map +1 -1
  68. package/dist/commands/datasets/alias/delete.js +1 -1
  69. package/dist/commands/datasets/alias/delete.js.map +1 -1
  70. package/dist/commands/datasets/alias/link.js +1 -1
  71. package/dist/commands/datasets/alias/link.js.map +1 -1
  72. package/dist/commands/datasets/alias/unlink.js +1 -1
  73. package/dist/commands/datasets/alias/unlink.js.map +1 -1
  74. package/dist/commands/datasets/copy.js +15 -1
  75. package/dist/commands/datasets/copy.js.map +1 -1
  76. package/dist/commands/datasets/create.js +1 -1
  77. package/dist/commands/datasets/create.js.map +1 -1
  78. package/dist/commands/datasets/delete.js +1 -1
  79. package/dist/commands/datasets/delete.js.map +1 -1
  80. package/dist/commands/datasets/embeddings/enable.js +11 -0
  81. package/dist/commands/datasets/embeddings/enable.js.map +1 -1
  82. package/dist/commands/datasets/export.js +2 -2
  83. package/dist/commands/datasets/export.js.map +1 -1
  84. package/dist/commands/datasets/list.js +2 -2
  85. package/dist/commands/datasets/list.js.map +1 -1
  86. package/dist/commands/debug.js +1 -1
  87. package/dist/commands/debug.js.map +1 -1
  88. package/dist/commands/deploy.js +3 -3
  89. package/dist/commands/deploy.js.map +1 -1
  90. package/dist/commands/dev.js +5 -5
  91. package/dist/commands/dev.js.map +1 -1
  92. package/dist/commands/docs/browse.js +1 -1
  93. package/dist/commands/docs/browse.js.map +1 -1
  94. package/dist/commands/documents/delete.js +1 -1
  95. package/dist/commands/documents/delete.js.map +1 -1
  96. package/dist/commands/exec.js +2 -2
  97. package/dist/commands/exec.js.map +1 -1
  98. package/dist/commands/graphql/deploy.js +2 -2
  99. package/dist/commands/graphql/deploy.js.map +1 -1
  100. package/dist/commands/graphql/list.js +2 -2
  101. package/dist/commands/graphql/list.js.map +1 -1
  102. package/dist/commands/hooks/create.js +2 -2
  103. package/dist/commands/hooks/create.js.map +1 -1
  104. package/dist/commands/hooks/delete.js +5 -5
  105. package/dist/commands/hooks/delete.js.map +1 -1
  106. package/dist/commands/hooks/list.js +3 -3
  107. package/dist/commands/hooks/list.js.map +1 -1
  108. package/dist/commands/hooks/logs.js +5 -5
  109. package/dist/commands/hooks/logs.js.map +1 -1
  110. package/dist/commands/init.js +175 -490
  111. package/dist/commands/init.js.map +1 -1
  112. package/dist/commands/install.js +1 -1
  113. package/dist/commands/install.js.map +1 -1
  114. package/dist/commands/learn.js +1 -1
  115. package/dist/commands/learn.js.map +1 -1
  116. package/dist/commands/login.js +1 -1
  117. package/dist/commands/login.js.map +1 -1
  118. package/dist/commands/logout.js +1 -1
  119. package/dist/commands/logout.js.map +1 -1
  120. package/dist/commands/manage.js +1 -1
  121. package/dist/commands/manage.js.map +1 -1
  122. package/dist/commands/manifest/extract.js +2 -2
  123. package/dist/commands/manifest/extract.js.map +1 -1
  124. package/dist/commands/mcp/configure.js +1 -1
  125. package/dist/commands/mcp/configure.js.map +1 -1
  126. package/dist/commands/media/delete-aspect.js +1 -1
  127. package/dist/commands/media/delete-aspect.js.map +1 -1
  128. package/dist/commands/media/export.js +1 -1
  129. package/dist/commands/media/export.js.map +1 -1
  130. package/dist/commands/preview.js +3 -3
  131. package/dist/commands/preview.js.map +1 -1
  132. package/dist/commands/projects/list.js +4 -2
  133. package/dist/commands/projects/list.js.map +1 -1
  134. package/dist/commands/schemas/deploy.js +3 -4
  135. package/dist/commands/schemas/deploy.js.map +1 -1
  136. package/dist/commands/schemas/extract.js +3 -3
  137. package/dist/commands/schemas/extract.js.map +1 -1
  138. package/dist/commands/schemas/list.js +4 -5
  139. package/dist/commands/schemas/list.js.map +1 -1
  140. package/dist/commands/telemetry/disable.js +2 -2
  141. package/dist/commands/telemetry/disable.js.map +1 -1
  142. package/dist/commands/telemetry/enable.js +2 -2
  143. package/dist/commands/telemetry/enable.js.map +1 -1
  144. package/dist/commands/telemetry/status.js +2 -2
  145. package/dist/commands/telemetry/status.js.map +1 -1
  146. package/dist/commands/tokens/add.js +1 -1
  147. package/dist/commands/tokens/add.js.map +1 -1
  148. package/dist/commands/tokens/delete.js +1 -1
  149. package/dist/commands/tokens/delete.js.map +1 -1
  150. package/dist/commands/tokens/list.js +2 -2
  151. package/dist/commands/tokens/list.js.map +1 -1
  152. package/dist/commands/users/list.js +1 -1
  153. package/dist/commands/users/list.js.map +1 -1
  154. package/dist/commands/versions.js +1 -1
  155. package/dist/commands/versions.js.map +1 -1
  156. package/dist/hooks/prerun/injectEnvVariables.js +3 -5
  157. package/dist/hooks/prerun/injectEnvVariables.js.map +1 -1
  158. package/dist/server/vite/plugin-sanity-build-entries.js +3 -2
  159. package/dist/server/vite/plugin-sanity-build-entries.js.map +1 -1
  160. package/dist/services/datasets.js +2 -1
  161. package/dist/services/datasets.js.map +1 -1
  162. package/dist/telemetry/init.telemetry.js.map +1 -1
  163. package/dist/util/packageManager/installationInfo/detectPackages.js +13 -7
  164. package/dist/util/packageManager/installationInfo/detectPackages.js.map +1 -1
  165. package/dist/util/telemetry/createTelemetryStore.js +27 -12
  166. package/dist/util/telemetry/createTelemetryStore.js.map +1 -1
  167. package/dist/util/update/fetchUpdateInfo.js +40 -0
  168. package/dist/util/update/fetchUpdateInfo.js.map +1 -0
  169. package/dist/util/update/fetchUpdateInfo.worker.js +19 -0
  170. package/dist/util/update/fetchUpdateInfo.worker.js.map +1 -0
  171. package/dist/util/update/getRunnerUpdateCommand.js +33 -0
  172. package/dist/util/update/getRunnerUpdateCommand.js.map +1 -0
  173. package/dist/util/update/getUpdateCommand.js +6 -7
  174. package/dist/util/update/getUpdateCommand.js.map +1 -1
  175. package/dist/util/update/packageRunner.js +10 -0
  176. package/dist/util/update/packageRunner.js.map +1 -0
  177. package/dist/util/update/resolveRunnerPackage.js +45 -0
  178. package/dist/util/update/resolveRunnerPackage.js.map +1 -0
  179. package/dist/util/update/resolveUpdateTarget.js +31 -0
  180. package/dist/util/update/resolveUpdateTarget.js.map +1 -0
  181. package/dist/util/update/showNotificationUpdate.js +8 -6
  182. package/dist/util/update/showNotificationUpdate.js.map +1 -1
  183. package/dist/util/update/updateChecker.js +73 -38
  184. package/dist/util/update/updateChecker.js.map +1 -1
  185. package/dist/util/validateProjection.js +121 -0
  186. package/dist/util/validateProjection.js.map +1 -0
  187. package/oclif.manifest.json +698 -681
  188. package/package.json +24 -23
  189. package/templates/app-quickstart/src/App.tsx +2 -2
  190. package/templates/app-sanity-ui/src/App.tsx +2 -2
  191. package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
  192. package/dist/util/update/fetchLatestVersion.js +0 -21
  193. package/dist/util/update/fetchLatestVersion.js.map +0 -1
@@ -28,17 +28,15 @@ export async function extractSchema(options) {
28
28
  trace.error(err);
29
29
  schemasExtractDebug('Failed to extract schema', err);
30
30
  spin.fail(enforceRequiredFields ? 'Failed to extract schema with enforced required fields' : 'Failed to extract schema');
31
- // Display validation errors if available
31
+ // Display validation errors if available and exit
32
32
  if (err instanceof SchemaExtractionError && err.validation && err.validation.length > 0) {
33
33
  output.log('');
34
34
  output.log(formatSchemaValidation(err.validation));
35
+ exit(1);
35
36
  }
36
- if (err instanceof Error) {
37
- output.error(err.message, {
38
- exit: 1
39
- });
40
- }
41
- exit(1);
37
+ output.error(err instanceof Error ? err.message : 'Failed to extract schema', {
38
+ exit: 1
39
+ });
42
40
  }
43
41
  }
44
42
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/extractSchema.ts"],"sourcesContent":["import {exit} from '@oclif/core/errors'\nimport {getCliTelemetry, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {SchemaExtractedTrace} from '../../telemetry/extractSchema.telemetry.js'\nimport {formatSchemaValidation} from './formatSchemaValidation.js'\nimport {type ExtractOptions} from './getExtractOptions.js'\nimport {runSchemaExtraction} from './runSchemaExtraction.js'\nimport {schemasExtractDebug} from './utils/debug.js'\nimport {SchemaExtractionError} from './utils/SchemaExtractionError.js'\n\ninterface ExtractSchemaActionOptions {\n extractOptions: ExtractOptions\n output: Output\n}\n\nexport async function extractSchema(options: ExtractSchemaActionOptions): Promise<void> {\n const {extractOptions, output} = options\n const {enforceRequiredFields, format, outputPath} = extractOptions\n\n const spin = spinner(\n enforceRequiredFields ? 'Extracting schema with enforced required fields' : 'Extracting schema',\n ).start()\n\n const trace = getCliTelemetry().trace(SchemaExtractedTrace)\n trace.start()\n\n try {\n spin.text = `Writing schema to ${outputPath}`\n\n const schema = await runSchemaExtraction(extractOptions)\n\n trace.log({\n enforceRequiredFields,\n schemaAllTypesCount: schema.length,\n schemaDocumentTypesCount: schema.filter((type) => type.type === 'document').length,\n schemaFormat: format,\n schemaTypesCount: schema.filter((type) => type.type === 'type').length,\n })\n\n spin.succeed(\n enforceRequiredFields\n ? `Extracted schema to ${outputPath} with enforced required fields`\n : `Extracted schema to ${outputPath}`,\n )\n\n trace.complete()\n } catch (err) {\n trace.error(err)\n schemasExtractDebug('Failed to extract schema', err)\n spin.fail(\n enforceRequiredFields\n ? 'Failed to extract schema with enforced required fields'\n : 'Failed to extract schema',\n )\n\n // Display validation errors if available\n if (err instanceof SchemaExtractionError && err.validation && err.validation.length > 0) {\n output.log('')\n output.log(formatSchemaValidation(err.validation))\n }\n\n if (err instanceof Error) {\n output.error(err.message, {exit: 1})\n }\n\n exit(1)\n }\n}\n"],"names":["exit","getCliTelemetry","spinner","SchemaExtractedTrace","formatSchemaValidation","runSchemaExtraction","schemasExtractDebug","SchemaExtractionError","extractSchema","options","extractOptions","output","enforceRequiredFields","format","outputPath","spin","start","trace","text","schema","log","schemaAllTypesCount","length","schemaDocumentTypesCount","filter","type","schemaFormat","schemaTypesCount","succeed","complete","err","error","fail","validation","Error","message"],"mappings":"AAAA,SAAQA,IAAI,QAAO,qBAAoB;AACvC,SAAQC,eAAe,QAAoB,mBAAkB;AAC7D,SAAQC,OAAO,QAAO,sBAAqB;AAE3C,SAAQC,oBAAoB,QAAO,6CAA4C;AAC/E,SAAQC,sBAAsB,QAAO,8BAA6B;AAElE,SAAQC,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,mBAAmB,QAAO,mBAAkB;AACpD,SAAQC,qBAAqB,QAAO,mCAAkC;AAOtE,OAAO,eAAeC,cAAcC,OAAmC;IACrE,MAAM,EAACC,cAAc,EAAEC,MAAM,EAAC,GAAGF;IACjC,MAAM,EAACG,qBAAqB,EAAEC,MAAM,EAAEC,UAAU,EAAC,GAAGJ;IAEpD,MAAMK,OAAOb,QACXU,wBAAwB,oDAAoD,qBAC5EI,KAAK;IAEP,MAAMC,QAAQhB,kBAAkBgB,KAAK,CAACd;IACtCc,MAAMD,KAAK;IAEX,IAAI;QACFD,KAAKG,IAAI,GAAG,CAAC,kBAAkB,EAAEJ,YAAY;QAE7C,MAAMK,SAAS,MAAMd,oBAAoBK;QAEzCO,MAAMG,GAAG,CAAC;YACRR;YACAS,qBAAqBF,OAAOG,MAAM;YAClCC,0BAA0BJ,OAAOK,MAAM,CAAC,CAACC,OAASA,KAAKA,IAAI,KAAK,YAAYH,MAAM;YAClFI,cAAcb;YACdc,kBAAkBR,OAAOK,MAAM,CAAC,CAACC,OAASA,KAAKA,IAAI,KAAK,QAAQH,MAAM;QACxE;QAEAP,KAAKa,OAAO,CACVhB,wBACI,CAAC,oBAAoB,EAAEE,WAAW,8BAA8B,CAAC,GACjE,CAAC,oBAAoB,EAAEA,YAAY;QAGzCG,MAAMY,QAAQ;IAChB,EAAE,OAAOC,KAAK;QACZb,MAAMc,KAAK,CAACD;QACZxB,oBAAoB,4BAA4BwB;QAChDf,KAAKiB,IAAI,CACPpB,wBACI,2DACA;QAGN,yCAAyC;QACzC,IAAIkB,eAAevB,yBAAyBuB,IAAIG,UAAU,IAAIH,IAAIG,UAAU,CAACX,MAAM,GAAG,GAAG;YACvFX,OAAOS,GAAG,CAAC;YACXT,OAAOS,GAAG,CAAChB,uBAAuB0B,IAAIG,UAAU;QAClD;QAEA,IAAIH,eAAeI,OAAO;YACxBvB,OAAOoB,KAAK,CAACD,IAAIK,OAAO,EAAE;gBAACnC,MAAM;YAAC;QACpC;QAEAA,KAAK;IACP;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/schema/extractSchema.ts"],"sourcesContent":["import {exit} from '@oclif/core/errors'\nimport {getCliTelemetry, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {SchemaExtractedTrace} from '../../telemetry/extractSchema.telemetry.js'\nimport {formatSchemaValidation} from './formatSchemaValidation.js'\nimport {type ExtractOptions} from './getExtractOptions.js'\nimport {runSchemaExtraction} from './runSchemaExtraction.js'\nimport {schemasExtractDebug} from './utils/debug.js'\nimport {SchemaExtractionError} from './utils/SchemaExtractionError.js'\n\ninterface ExtractSchemaActionOptions {\n extractOptions: ExtractOptions\n output: Output\n}\n\nexport async function extractSchema(options: ExtractSchemaActionOptions): Promise<void> {\n const {extractOptions, output} = options\n const {enforceRequiredFields, format, outputPath} = extractOptions\n\n const spin = spinner(\n enforceRequiredFields ? 'Extracting schema with enforced required fields' : 'Extracting schema',\n ).start()\n\n const trace = getCliTelemetry().trace(SchemaExtractedTrace)\n trace.start()\n\n try {\n spin.text = `Writing schema to ${outputPath}`\n\n const schema = await runSchemaExtraction(extractOptions)\n\n trace.log({\n enforceRequiredFields,\n schemaAllTypesCount: schema.length,\n schemaDocumentTypesCount: schema.filter((type) => type.type === 'document').length,\n schemaFormat: format,\n schemaTypesCount: schema.filter((type) => type.type === 'type').length,\n })\n\n spin.succeed(\n enforceRequiredFields\n ? `Extracted schema to ${outputPath} with enforced required fields`\n : `Extracted schema to ${outputPath}`,\n )\n\n trace.complete()\n } catch (err) {\n trace.error(err)\n schemasExtractDebug('Failed to extract schema', err)\n spin.fail(\n enforceRequiredFields\n ? 'Failed to extract schema with enforced required fields'\n : 'Failed to extract schema',\n )\n\n // Display validation errors if available and exit\n if (err instanceof SchemaExtractionError && err.validation && err.validation.length > 0) {\n output.log('')\n output.log(formatSchemaValidation(err.validation))\n exit(1)\n }\n\n output.error(err instanceof Error ? err.message : 'Failed to extract schema', {exit: 1})\n }\n}\n"],"names":["exit","getCliTelemetry","spinner","SchemaExtractedTrace","formatSchemaValidation","runSchemaExtraction","schemasExtractDebug","SchemaExtractionError","extractSchema","options","extractOptions","output","enforceRequiredFields","format","outputPath","spin","start","trace","text","schema","log","schemaAllTypesCount","length","schemaDocumentTypesCount","filter","type","schemaFormat","schemaTypesCount","succeed","complete","err","error","fail","validation","Error","message"],"mappings":"AAAA,SAAQA,IAAI,QAAO,qBAAoB;AACvC,SAAQC,eAAe,QAAoB,mBAAkB;AAC7D,SAAQC,OAAO,QAAO,sBAAqB;AAE3C,SAAQC,oBAAoB,QAAO,6CAA4C;AAC/E,SAAQC,sBAAsB,QAAO,8BAA6B;AAElE,SAAQC,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,mBAAmB,QAAO,mBAAkB;AACpD,SAAQC,qBAAqB,QAAO,mCAAkC;AAOtE,OAAO,eAAeC,cAAcC,OAAmC;IACrE,MAAM,EAACC,cAAc,EAAEC,MAAM,EAAC,GAAGF;IACjC,MAAM,EAACG,qBAAqB,EAAEC,MAAM,EAAEC,UAAU,EAAC,GAAGJ;IAEpD,MAAMK,OAAOb,QACXU,wBAAwB,oDAAoD,qBAC5EI,KAAK;IAEP,MAAMC,QAAQhB,kBAAkBgB,KAAK,CAACd;IACtCc,MAAMD,KAAK;IAEX,IAAI;QACFD,KAAKG,IAAI,GAAG,CAAC,kBAAkB,EAAEJ,YAAY;QAE7C,MAAMK,SAAS,MAAMd,oBAAoBK;QAEzCO,MAAMG,GAAG,CAAC;YACRR;YACAS,qBAAqBF,OAAOG,MAAM;YAClCC,0BAA0BJ,OAAOK,MAAM,CAAC,CAACC,OAASA,KAAKA,IAAI,KAAK,YAAYH,MAAM;YAClFI,cAAcb;YACdc,kBAAkBR,OAAOK,MAAM,CAAC,CAACC,OAASA,KAAKA,IAAI,KAAK,QAAQH,MAAM;QACxE;QAEAP,KAAKa,OAAO,CACVhB,wBACI,CAAC,oBAAoB,EAAEE,WAAW,8BAA8B,CAAC,GACjE,CAAC,oBAAoB,EAAEA,YAAY;QAGzCG,MAAMY,QAAQ;IAChB,EAAE,OAAOC,KAAK;QACZb,MAAMc,KAAK,CAACD;QACZxB,oBAAoB,4BAA4BwB;QAChDf,KAAKiB,IAAI,CACPpB,wBACI,2DACA;QAGN,kDAAkD;QAClD,IAAIkB,eAAevB,yBAAyBuB,IAAIG,UAAU,IAAIH,IAAIG,UAAU,CAACX,MAAM,GAAG,GAAG;YACvFX,OAAOS,GAAG,CAAC;YACXT,OAAOS,GAAG,CAAChB,uBAAuB0B,IAAIG,UAAU;YAChDjC,KAAK;QACP;QAEAW,OAAOoB,KAAK,CAACD,eAAeI,QAAQJ,IAAIK,OAAO,GAAG,4BAA4B;YAACnC,MAAM;QAAC;IACxF;AACF"}
@@ -1,13 +1,13 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/mini';
2
2
  export const extractSchemaWorkerData = z.object({
3
3
  configPath: z.string(),
4
4
  enforceRequiredFields: z.boolean(),
5
5
  workDir: z.string(),
6
- workspaceName: z.string().optional()
6
+ workspaceName: z.optional(z.string())
7
7
  });
8
8
  export const uniqWorkspaceWorkerDataSchema = z.object({
9
9
  configPath: z.string(),
10
- dataset: z.string().optional()
10
+ dataset: z.optional(z.string())
11
11
  });
12
12
  export const extractWorkspaceWorkerData = z.object({
13
13
  configPath: z.string(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/types.ts"],"sourcesContent":["import {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {z} from 'zod'\n\nexport const extractSchemaWorkerData = z.object({\n configPath: z.string(),\n enforceRequiredFields: z.boolean(),\n workDir: z.string(),\n workspaceName: z.string().optional(),\n})\n\nexport type ExtractSchemaWorkerData = z.infer<typeof extractSchemaWorkerData>\n\n/**\n * Contains debug information about the serialized schema.\n *\n * @internal\n **/\nexport type SerializedSchemaDebug = {\n hoisted: Record<string, SerializedTypeDebug>\n parent?: SerializedSchemaDebug\n size: number\n types: Record<string, SerializedTypeDebug>\n}\n\n/**\n * Contains debug information about a serialized type.\n *\n * @internal\n **/\nexport type SerializedTypeDebug = {\n extends: string\n fields?: Record<string, SerializedTypeDebug>\n of?: Record<string, SerializedTypeDebug>\n size: number\n}\n\n/** @internal */\nexport interface ExtractSchemaWorkerError {\n error: string\n type: 'error'\n\n validation?: SchemaValidationProblemGroup[]\n}\n\nexport const uniqWorkspaceWorkerDataSchema = z.object({\n configPath: z.string(),\n dataset: z.string().optional(),\n})\n\nexport type UniqWorkspaceWorkerData = z.infer<typeof uniqWorkspaceWorkerDataSchema>\n\nexport const extractWorkspaceWorkerData = z.object({\n configPath: z.string(),\n workDir: z.string(),\n})\n\nexport type ExtractWorkspaceWorkerData = z.infer<typeof extractWorkspaceWorkerData>\n"],"names":["z","extractSchemaWorkerData","object","configPath","string","enforceRequiredFields","boolean","workDir","workspaceName","optional","uniqWorkspaceWorkerDataSchema","dataset","extractWorkspaceWorkerData"],"mappings":"AACA,SAAQA,CAAC,QAAO,MAAK;AAErB,OAAO,MAAMC,0BAA0BD,EAAEE,MAAM,CAAC;IAC9CC,YAAYH,EAAEI,MAAM;IACpBC,uBAAuBL,EAAEM,OAAO;IAChCC,SAASP,EAAEI,MAAM;IACjBI,eAAeR,EAAEI,MAAM,GAAGK,QAAQ;AACpC,GAAE;AAoCF,OAAO,MAAMC,gCAAgCV,EAAEE,MAAM,CAAC;IACpDC,YAAYH,EAAEI,MAAM;IACpBO,SAASX,EAAEI,MAAM,GAAGK,QAAQ;AAC9B,GAAE;AAIF,OAAO,MAAMG,6BAA6BZ,EAAEE,MAAM,CAAC;IACjDC,YAAYH,EAAEI,MAAM;IACpBG,SAASP,EAAEI,MAAM;AACnB,GAAE"}
1
+ {"version":3,"sources":["../../../src/actions/schema/types.ts"],"sourcesContent":["import {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {z} from 'zod/mini'\n\nexport const extractSchemaWorkerData = z.object({\n configPath: z.string(),\n enforceRequiredFields: z.boolean(),\n workDir: z.string(),\n workspaceName: z.optional(z.string()),\n})\n\nexport type ExtractSchemaWorkerData = z.infer<typeof extractSchemaWorkerData>\n\n/**\n * Contains debug information about the serialized schema.\n *\n * @internal\n **/\nexport type SerializedSchemaDebug = {\n hoisted: Record<string, SerializedTypeDebug>\n parent?: SerializedSchemaDebug\n size: number\n types: Record<string, SerializedTypeDebug>\n}\n\n/**\n * Contains debug information about a serialized type.\n *\n * @internal\n **/\nexport type SerializedTypeDebug = {\n extends: string\n fields?: Record<string, SerializedTypeDebug>\n of?: Record<string, SerializedTypeDebug>\n size: number\n}\n\n/** @internal */\nexport interface ExtractSchemaWorkerError {\n error: string\n type: 'error'\n\n validation?: SchemaValidationProblemGroup[]\n}\n\nexport const uniqWorkspaceWorkerDataSchema = z.object({\n configPath: z.string(),\n dataset: z.optional(z.string()),\n})\n\nexport type UniqWorkspaceWorkerData = z.infer<typeof uniqWorkspaceWorkerDataSchema>\n\nexport const extractWorkspaceWorkerData = z.object({\n configPath: z.string(),\n workDir: z.string(),\n})\n\nexport type ExtractWorkspaceWorkerData = z.infer<typeof extractWorkspaceWorkerData>\n"],"names":["z","extractSchemaWorkerData","object","configPath","string","enforceRequiredFields","boolean","workDir","workspaceName","optional","uniqWorkspaceWorkerDataSchema","dataset","extractWorkspaceWorkerData"],"mappings":"AACA,SAAQA,CAAC,QAAO,WAAU;AAE1B,OAAO,MAAMC,0BAA0BD,EAAEE,MAAM,CAAC;IAC9CC,YAAYH,EAAEI,MAAM;IACpBC,uBAAuBL,EAAEM,OAAO;IAChCC,SAASP,EAAEI,MAAM;IACjBI,eAAeR,EAAES,QAAQ,CAACT,EAAEI,MAAM;AACpC,GAAE;AAoCF,OAAO,MAAMM,gCAAgCV,EAAEE,MAAM,CAAC;IACpDC,YAAYH,EAAEI,MAAM;IACpBO,SAASX,EAAES,QAAQ,CAACT,EAAEI,MAAM;AAC9B,GAAE;AAIF,OAAO,MAAMQ,6BAA6BZ,EAAEE,MAAM,CAAC;IACjDC,YAAYH,EAAEI,MAAM;IACpBG,SAASP,EAAEI,MAAM;AACnB,GAAE"}
@@ -1,10 +1,10 @@
1
- import { z } from 'zod';
1
+ import { z } from 'zod/mini';
2
2
  export function validateEmail(email) {
3
3
  const trimmedEmail = email.trim();
4
4
  if (!trimmedEmail) {
5
5
  return 'Email is required';
6
6
  }
7
- const validatedEmail = z.string().email().safeParse(trimmedEmail);
7
+ const validatedEmail = z.email().safeParse(trimmedEmail);
8
8
  if (!validatedEmail.success) {
9
9
  return 'Please enter a valid email address';
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/users/validateEmail.ts"],"sourcesContent":["import {z} from 'zod'\n\nexport function validateEmail(email: string): string | true {\n const trimmedEmail = email.trim()\n if (!trimmedEmail) {\n return 'Email is required'\n }\n\n const validatedEmail = z.string().email().safeParse(trimmedEmail)\n if (!validatedEmail.success) {\n return 'Please enter a valid email address'\n }\n\n return true\n}\n"],"names":["z","validateEmail","email","trimmedEmail","trim","validatedEmail","string","safeParse","success"],"mappings":"AAAA,SAAQA,CAAC,QAAO,MAAK;AAErB,OAAO,SAASC,cAAcC,KAAa;IACzC,MAAMC,eAAeD,MAAME,IAAI;IAC/B,IAAI,CAACD,cAAc;QACjB,OAAO;IACT;IAEA,MAAME,iBAAiBL,EAAEM,MAAM,GAAGJ,KAAK,GAAGK,SAAS,CAACJ;IACpD,IAAI,CAACE,eAAeG,OAAO,EAAE;QAC3B,OAAO;IACT;IAEA,OAAO;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/users/validateEmail.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nexport function validateEmail(email: string): string | true {\n const trimmedEmail = email.trim()\n if (!trimmedEmail) {\n return 'Email is required'\n }\n\n const validatedEmail = z.email().safeParse(trimmedEmail)\n if (!validatedEmail.success) {\n return 'Please enter a valid email address'\n }\n\n return true\n}\n"],"names":["z","validateEmail","email","trimmedEmail","trim","validatedEmail","safeParse","success"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,OAAO,SAASC,cAAcC,KAAa;IACzC,MAAMC,eAAeD,MAAME,IAAI;IAC/B,IAAI,CAACD,cAAc;QACjB,OAAO;IACT;IAEA,MAAME,iBAAiBL,EAAEE,KAAK,GAAGI,SAAS,CAACH;IAC3C,IAAI,CAACE,eAAeE,OAAO,EAAE;QAC3B,OAAO;IACT;IAEA,OAAO;AACT"}
@@ -15,7 +15,7 @@ export class DisableBackupCommand extends SanityCommand {
15
15
  required: false
16
16
  })
17
17
  };
18
- static description = 'Disable backup for a dataset.';
18
+ static description = 'Disable backup for a dataset';
19
19
  static examples = [
20
20
  {
21
21
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/backups/disable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst disableBackupDebug = subdebug('backup:disable')\n\nexport class DisableBackupCommand extends SanityCommand<typeof DisableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to disable backup for',\n required: false,\n }),\n }\n\n static override description = 'Disable backup for a dataset.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively disable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Disable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to disable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:disable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DisableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n try {\n await setBackup({dataset, projectId, status: false})\n\n this.log(`${styleText('green', `Disabled daily backups for dataset ${dataset}.\\n`)}`)\n this.log(\n `${styleText('yellow', 'Note: Existing backups will be retained according to your retention policy.\\n')}`,\n )\n\n disableBackupDebug(`Successfully disabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to disable backup for dataset`, error)\n this.error(`Disabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n const err = error as Error\n disableBackupDebug(`Error fetching datasets`, err)\n this.error(`Failed to fetch datasets:\\n${err.message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","select","assertDatasetExists","promptForProject","setBackup","listDatasets","getProjectIdFlag","disableBackupDebug","DisableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","promptForDataset","status","log","choices","map","name","value","err"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,IAAI,QAAO,cAAa;AAChC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,MAAM,QAAO,sBAAqB;AAG1C,SAAQC,mBAAmB,QAAO,6CAA4C;AAC9E,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,SAAS,QAAO,2BAA0B;AAClD,SAAQC,YAAY,QAAO,6BAA4B;AACvD,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,qBAAqBP,SAAS;AAEpC,OAAO,MAAMQ,6BAA6BT;IACxC,OAAgBU,OAAO;QACrBC,SAASZ,KAAKa,MAAM,CAAC;YACnBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,gCAA+B;IAE7D,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGV,iBAAiB;YAClBM,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAC;IAED,OAAgBC,gBAA0B;QAAC;KAAiB,CAAA;IAE5D,MAAaC,MAAqB;QAChC,MAAM,EAACV,IAAI,EAAC,GAAG,MAAM,IAAI,CAACW,KAAK,CAACZ;QAChC,IAAI,EAACE,OAAO,EAAC,GAAGD;QAEhB,MAAMY,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRpB,iBAAiB;oBACfqB,qBAAqB;wBACnB;4BAACC,OAAO;4BAAQC,YAAY;wBAAyB;wBACrD;4BAACD,OAAO;4BAAUC,YAAY;wBAAyB;qBACxD;gBACH;QACJ;QAEA,IAAIC;QAEJ,IAAI;YACFA,WAAW,MAAMtB,aAAagB;QAChC,EAAE,OAAOO,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;YAChErB,mBAAmB,CAAC,yBAAyB,EAAEsB,SAAS,EAAED;YAC1D,IAAI,CAACA,KAAK,CAAC,CAAC,yBAAyB,EAAEC,SAAS,EAAE;gBAACG,MAAM;YAAC;QAC5D;QAEA,IAAIL,SAASM,MAAM,KAAK,GAAG;YACzB,IAAI,CAACL,KAAK,CAAC,sCAAsC;gBAACI,MAAM;YAAC;QAC3D;QAEA,IAAItB,SAAS;YACXR,oBAAoByB,UAAUjB;QAChC,OAAO;YACLA,UAAU,MAAM,IAAI,CAACwB,gBAAgB,CAACP;QACxC;QAEA,IAAI;YACF,MAAMvB,UAAU;gBAACM;gBAASW;gBAAWc,QAAQ;YAAK;YAElD,IAAI,CAACC,GAAG,CAAC,GAAGvC,UAAU,SAAS,CAAC,mCAAmC,EAAEa,QAAQ,GAAG,CAAC,GAAG;YACpF,IAAI,CAAC0B,GAAG,CACN,GAAGvC,UAAU,UAAU,kFAAkF;YAG3GU,mBAAmB,CAAC,yCAAyC,EAAEG,SAAS;QAC1E,EAAE,OAAOkB,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;YAChErB,mBAAmB,CAAC,oCAAoC,CAAC,EAAEqB;YAC3D,IAAI,CAACA,KAAK,CAAC,CAAC,iCAAiC,EAAEC,SAAS,EAAE;gBAACG,MAAM;YAAC;QACpE;IACF;IAEA,MAAcE,iBAAiBP,QAA0B,EAAmB;QAC1E,IAAI;YACF,MAAMU,UAAUV,SAASW,GAAG,CAAC,CAAC5B,UAAa,CAAA;oBACzC6B,MAAM7B,QAAQ6B,IAAI;oBAClBC,OAAO9B,QAAQ6B,IAAI;gBACrB,CAAA;YAEA,OAAOtC,OAAO;gBACZoC;gBACAR,SAAS;YACX;QACF,EAAE,OAAOD,OAAO;YACd,MAAMa,MAAMb;YACZrB,mBAAmB,CAAC,uBAAuB,CAAC,EAAEkC;YAC9C,IAAI,CAACb,KAAK,CAAC,CAAC,2BAA2B,EAAEa,IAAIZ,OAAO,EAAE,EAAE;gBAACG,MAAM;YAAC;QAClE;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/backups/disable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst disableBackupDebug = subdebug('backup:disable')\n\nexport class DisableBackupCommand extends SanityCommand<typeof DisableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to disable backup for',\n required: false,\n }),\n }\n\n static override description = 'Disable backup for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively disable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Disable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to disable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:disable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DisableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n try {\n await setBackup({dataset, projectId, status: false})\n\n this.log(`${styleText('green', `Disabled daily backups for dataset ${dataset}.\\n`)}`)\n this.log(\n `${styleText('yellow', 'Note: Existing backups will be retained according to your retention policy.\\n')}`,\n )\n\n disableBackupDebug(`Successfully disabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to disable backup for dataset`, error)\n this.error(`Disabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n const err = error as Error\n disableBackupDebug(`Error fetching datasets`, err)\n this.error(`Failed to fetch datasets:\\n${err.message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","select","assertDatasetExists","promptForProject","setBackup","listDatasets","getProjectIdFlag","disableBackupDebug","DisableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","promptForDataset","status","log","choices","map","name","value","err"],"mappings":"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"}
@@ -34,7 +34,7 @@ export class DownloadBackupCommand extends SanityCommand {
34
34
  required: false
35
35
  })
36
36
  };
37
- static description = 'Download a dataset backup to a local file.';
37
+ static description = 'Download a dataset backup to a local file';
38
38
  static examples = [
39
39
  {
40
40
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': Flags.string({\n description: 'The backup ID to download',\n }),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: 1})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: 1})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const inputResult = await input({\n default: path.join(workDir, defaultOutFileName),\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: 1})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`concurrency should be in 1 to ${MAX_DOWNLOAD_CONCURRENCY} range`, {exit: 1})\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: 1})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: 1})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","SanityCommand","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","inputResult","promptForBackupId","exists","then","shouldOverwrite","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': Flags.string({\n description: 'The backup ID to download',\n }),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: 1})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: 1})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const inputResult = await input({\n default: path.join(workDir, defaultOutFileName),\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: 1})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`concurrency should be in 1 to ${MAX_DOWNLOAD_CONCURRENCY} range`, {exit: 1})\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: 1})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: 1})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","SanityCommand","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","inputResult","promptForBackupId","exists","then","shouldOverwrite","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
@@ -16,7 +16,7 @@ export class EnableBackupCommand extends SanityCommand {
16
16
  required: false
17
17
  })
18
18
  };
19
- static description = 'Enable backup for a dataset.';
19
+ static description = 'Enable backup for a dataset';
20
20
  static examples = [
21
21
  {
22
22
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/backups/enable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst enableBackupDebug = subdebug('backup:enable')\n\nexport class EnableBackupCommand extends SanityCommand<typeof EnableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to enable backup for',\n required: false,\n }),\n }\n\n static override description = 'Enable backup for a dataset.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively enable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Enable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to enable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:enable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(EnableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n const hasProduction = datasets.some((dataset) => dataset.name === 'production')\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: true, datasets})\n\n if (dataset === NEW_DATASET_VALUE) {\n const newDatasetName = await promptForDatasetName({\n default: hasProduction ? undefined : 'production',\n })\n\n try {\n await createDataset({\n datasetName: newDatasetName,\n projectId,\n })\n dataset = newDatasetName\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to create dataset ${newDatasetName}: ${message}`, error)\n this.error(`Failed to create dataset ${newDatasetName}: ${message}`, {exit: 1})\n }\n }\n }\n\n try {\n await setBackup({dataset, projectId, status: true})\n\n this.log(\n `${styleText(\n 'green',\n `Enabled backups for dataset ${dataset}.\\nPlease note that it may take up to 24 hours before the first backup is created.\\n`,\n )}`,\n )\n\n this.log(\n `${styleText('bold', `Retention policies may apply depending on your plan and agreement.\\n`)}`,\n )\n\n enableBackupDebug(`Successfully enabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to enable backup for dataset`, error)\n this.error(`Enabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","assertDatasetExists","NEW_DATASET_VALUE","promptForDataset","promptForDatasetName","promptForProject","setBackup","createDataset","listDatasets","getProjectIdFlag","enableBackupDebug","EnableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","hasProduction","some","name","length","allowCreation","newDatasetName","default","undefined","datasetName","status","log"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/backups/enable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst enableBackupDebug = subdebug('backup:enable')\n\nexport class EnableBackupCommand extends SanityCommand<typeof EnableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to enable backup for',\n required: false,\n }),\n }\n\n static override description = 'Enable backup for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively enable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Enable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to enable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:enable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(EnableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n const hasProduction = datasets.some((dataset) => dataset.name === 'production')\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: true, datasets})\n\n if (dataset === NEW_DATASET_VALUE) {\n const newDatasetName = await promptForDatasetName({\n default: hasProduction ? undefined : 'production',\n })\n\n try {\n await createDataset({\n datasetName: newDatasetName,\n projectId,\n })\n dataset = newDatasetName\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to create dataset ${newDatasetName}: ${message}`, error)\n this.error(`Failed to create dataset ${newDatasetName}: ${message}`, {exit: 1})\n }\n }\n }\n\n try {\n await setBackup({dataset, projectId, status: true})\n\n this.log(\n `${styleText(\n 'green',\n `Enabled backups for dataset ${dataset}.\\nPlease note that it may take up to 24 hours before the first backup is created.\\n`,\n )}`,\n )\n\n this.log(\n `${styleText('bold', `Retention policies may apply depending on your plan and agreement.\\n`)}`,\n )\n\n enableBackupDebug(`Successfully enabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to enable backup for dataset`, error)\n this.error(`Enabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","assertDatasetExists","NEW_DATASET_VALUE","promptForDataset","promptForDatasetName","promptForProject","setBackup","createDataset","listDatasets","getProjectIdFlag","enableBackupDebug","EnableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","hasProduction","some","name","length","allowCreation","newDatasetName","default","undefined","datasetName","status","log"],"mappings":"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"}
@@ -20,7 +20,7 @@ export class ListBackupCommand extends SanityCommand {
20
20
  required: false
21
21
  })
22
22
  };
23
- static description = 'List available backups for a dataset.';
23
+ static description = 'List available backups for a dataset';
24
24
  static examples = [
25
25
  {
26
26
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/backups/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport {Table} from 'console-table-printer'\nimport {isAfter} from 'date-fns/isAfter'\nimport {isValid} from 'date-fns/isValid'\nimport {lightFormat} from 'date-fns/lightFormat'\nimport {parse} from 'date-fns/parse'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listBackupDebug = subdebug('backup:list')\n\nconst DEFAULT_LIST_BACKUP_LIMIT = 30\n\ntype ListBackupRequestQueryParams = {\n after?: string\n before?: string\n limit: string\n}\n\nexport class ListBackupCommand extends SanityCommand<typeof ListBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to list backups for',\n required: false,\n }),\n }\n\n static override description = 'List available backups for a dataset.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List backups for a dataset interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'List backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --limit 50',\n description: 'List up to 50 backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --after 2024-01-31 --limit 10',\n description: 'List up to 10 backups created after 2024-01-31',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list backups for',\n semantics: 'override',\n }),\n after: Flags.string({\n description: 'Only return backups after this date (inclusive, YYYY-MM-DD format)',\n }),\n before: Flags.string({\n description: 'Only return backups before this date (exclusive, YYYY-MM-DD format)',\n }),\n limit: Flags.integer({\n char: 'l',\n default: DEFAULT_LIST_BACKUP_LIMIT,\n description: 'Maximum number of backups returned',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:list']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ListBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n // Validate date flags\n if (flags.before || flags.after) {\n try {\n const parsedBefore = this.processDateFlag(flags.before, 'before')\n const parsedAfter = this.processDateFlag(flags.after, 'after')\n\n if (parsedAfter && parsedBefore && isAfter(parsedAfter, parsedBefore)) {\n this.error('--after date must be before --before', {exit: 1})\n }\n } catch (err) {\n this.error(`Parsing date flags: ${err instanceof Error ? err.message : err}`, {exit: 1})\n }\n }\n\n // Validate limit flag\n if (flags.limit < 1 || flags.limit > Number.MAX_SAFE_INTEGER) {\n this.error(`Parsing --limit: must be an integer between 1 and ${Number.MAX_SAFE_INTEGER}`, {\n exit: 1,\n })\n }\n\n const query: ListBackupRequestQueryParams = {\n limit: flags.limit.toString(),\n }\n\n if (flags.after) {\n query.after = flags.after\n }\n\n if (flags.before) {\n query.before = flags.before\n }\n\n try {\n const response = await listBackups({\n after: flags.after,\n before: flags.before,\n datasetName: dataset,\n limit: flags.limit,\n projectId,\n })\n\n if (response.backups.length === 0) {\n this.log('No backups found.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'resource', title: 'RESOURCE'},\n {alignment: 'left', name: 'createdAt', title: 'CREATED AT'},\n {alignment: 'left', name: 'backupId', title: 'BACKUP ID'},\n ],\n })\n\n for (const backup of response.backups) {\n const {createdAt, id} = backup\n table.addRow({\n backupId: id,\n createdAt: lightFormat(Date.parse(createdAt), 'yyyy-MM-dd HH:mm:ss'),\n resource: 'Dataset',\n })\n }\n\n table.printTable()\n\n listBackupDebug(\n `Successfully listed ${response.backups.length} backups for dataset ${dataset}`,\n )\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list backups for dataset ${dataset}:`, error)\n this.error(`List dataset backup failed: ${message}`, {exit: 1})\n }\n }\n\n private processDateFlag(date: string | undefined, flagName: string): Date | undefined {\n if (!date) return undefined\n const parsedDate = parse(date, 'yyyy-MM-dd', new Date())\n if (isValid(parsedDate)) {\n return parsedDate\n }\n\n throw new Error(`Invalid date format for '--${flagName}' flag. Use YYYY-MM-DD`)\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n listBackupDebug(`Error selecting dataset`, error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n }\n}\n"],"names":["Args","Flags","SanityCommand","subdebug","select","Table","isAfter","isValid","lightFormat","parse","assertDatasetExists","promptForProject","listBackups","listDatasets","getProjectIdFlag","listBackupDebug","DEFAULT_LIST_BACKUP_LIMIT","ListBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","after","before","limit","integer","char","default","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","promptForDataset","parsedBefore","processDateFlag","parsedAfter","err","Number","MAX_SAFE_INTEGER","query","toString","response","datasetName","backups","log","table","columns","alignment","name","title","backup","createdAt","id","addRow","backupId","Date","resource","printTable","date","flagName","undefined","parsedDate","choices","map","value"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/backups/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport {Table} from 'console-table-printer'\nimport {isAfter} from 'date-fns/isAfter'\nimport {isValid} from 'date-fns/isValid'\nimport {lightFormat} from 'date-fns/lightFormat'\nimport {parse} from 'date-fns/parse'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listBackupDebug = subdebug('backup:list')\n\nconst DEFAULT_LIST_BACKUP_LIMIT = 30\n\ntype ListBackupRequestQueryParams = {\n after?: string\n before?: string\n limit: string\n}\n\nexport class ListBackupCommand extends SanityCommand<typeof ListBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to list backups for',\n required: false,\n }),\n }\n\n static override description = 'List available backups for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List backups for a dataset interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'List backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --limit 50',\n description: 'List up to 50 backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --after 2024-01-31 --limit 10',\n description: 'List up to 10 backups created after 2024-01-31',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list backups for',\n semantics: 'override',\n }),\n after: Flags.string({\n description: 'Only return backups after this date (inclusive, YYYY-MM-DD format)',\n }),\n before: Flags.string({\n description: 'Only return backups before this date (exclusive, YYYY-MM-DD format)',\n }),\n limit: Flags.integer({\n char: 'l',\n default: DEFAULT_LIST_BACKUP_LIMIT,\n description: 'Maximum number of backups returned',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:list']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ListBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n // Validate date flags\n if (flags.before || flags.after) {\n try {\n const parsedBefore = this.processDateFlag(flags.before, 'before')\n const parsedAfter = this.processDateFlag(flags.after, 'after')\n\n if (parsedAfter && parsedBefore && isAfter(parsedAfter, parsedBefore)) {\n this.error('--after date must be before --before', {exit: 1})\n }\n } catch (err) {\n this.error(`Parsing date flags: ${err instanceof Error ? err.message : err}`, {exit: 1})\n }\n }\n\n // Validate limit flag\n if (flags.limit < 1 || flags.limit > Number.MAX_SAFE_INTEGER) {\n this.error(`Parsing --limit: must be an integer between 1 and ${Number.MAX_SAFE_INTEGER}`, {\n exit: 1,\n })\n }\n\n const query: ListBackupRequestQueryParams = {\n limit: flags.limit.toString(),\n }\n\n if (flags.after) {\n query.after = flags.after\n }\n\n if (flags.before) {\n query.before = flags.before\n }\n\n try {\n const response = await listBackups({\n after: flags.after,\n before: flags.before,\n datasetName: dataset,\n limit: flags.limit,\n projectId,\n })\n\n if (response.backups.length === 0) {\n this.log('No backups found.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'resource', title: 'RESOURCE'},\n {alignment: 'left', name: 'createdAt', title: 'CREATED AT'},\n {alignment: 'left', name: 'backupId', title: 'BACKUP ID'},\n ],\n })\n\n for (const backup of response.backups) {\n const {createdAt, id} = backup\n table.addRow({\n backupId: id,\n createdAt: lightFormat(Date.parse(createdAt), 'yyyy-MM-dd HH:mm:ss'),\n resource: 'Dataset',\n })\n }\n\n table.printTable()\n\n listBackupDebug(\n `Successfully listed ${response.backups.length} backups for dataset ${dataset}`,\n )\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list backups for dataset ${dataset}:`, error)\n this.error(`List dataset backup failed: ${message}`, {exit: 1})\n }\n }\n\n private processDateFlag(date: string | undefined, flagName: string): Date | undefined {\n if (!date) return undefined\n const parsedDate = parse(date, 'yyyy-MM-dd', new Date())\n if (isValid(parsedDate)) {\n return parsedDate\n }\n\n throw new Error(`Invalid date format for '--${flagName}' flag. Use YYYY-MM-DD`)\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n listBackupDebug(`Error selecting dataset`, error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n }\n}\n"],"names":["Args","Flags","SanityCommand","subdebug","select","Table","isAfter","isValid","lightFormat","parse","assertDatasetExists","promptForProject","listBackups","listDatasets","getProjectIdFlag","listBackupDebug","DEFAULT_LIST_BACKUP_LIMIT","ListBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","after","before","limit","integer","char","default","hiddenAliases","run","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","promptForDataset","parsedBefore","processDateFlag","parsedAfter","err","Number","MAX_SAFE_INTEGER","query","toString","response","datasetName","backups","log","table","columns","alignment","name","title","backup","createdAt","id","addRow","backupId","Date","resource","printTable","date","flagName","undefined","parsedDate","choices","map","value"],"mappings":"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"}
@@ -11,7 +11,7 @@ export class BuildCommand extends SanityCommand {
11
11
  description: 'Output directory'
12
12
  })
13
13
  };
14
- static description = 'Builds the Sanity Studio configuration into a static bundle';
14
+ static description = 'Build Sanity Studio into a static bundle';
15
15
  static examples = [
16
16
  '<%= config.bin %> <%= command.id %>',
17
17
  '<%= config.bin %> <%= command.id %> --no-minify --source-maps'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/build.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\n\nimport {buildApp} from '../actions/build/buildApp.js'\nimport {buildDebug} from '../actions/build/buildDebug.js'\nimport {buildStudio} from '../actions/build/buildStudio.js'\nimport {shouldAutoUpdate} from '../actions/build/shouldAutoUpdate.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class BuildCommand extends SanityCommand<typeof BuildCommand> {\n static override args = {\n outputDir: Args.directory({description: 'Output directory'}),\n }\n\n static override description = 'Builds the Sanity Studio configuration into a static bundle'\n\n static override examples = [\n '<%= config.bin %> <%= command.id %>',\n '<%= config.bin %> <%= command.id %> --no-minify --source-maps',\n ]\n\n static override flags = {\n 'auto-updates': Flags.boolean({\n allowNo: true,\n description: 'Enable/disable auto updates of studio versions',\n }),\n minify: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Enable/disable minifying of built bundles',\n }),\n 'source-maps': Flags.boolean({\n allowNo: true,\n default: false,\n description: 'Enable source maps for built bundles (increases size of bundle)',\n }),\n stats: Flags.boolean({\n default: false,\n description: 'Show stats about the built bundles',\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 cliConfig = await this.getCliConfig()\n\n const {flags} = await this.parse(BuildCommand)\n\n const isApp = determineIsApp(cliConfig)\n\n const workDir = (await this.getProjectRoot()).directory\n\n const output = this.output\n\n const autoUpdatesEnabled = shouldAutoUpdate({cliConfig, flags, output})\n\n if (isApp) {\n buildDebug(`Building app`)\n await buildApp({\n autoUpdatesEnabled,\n cliConfig,\n flags,\n outDir: this.args.outputDir,\n output,\n workDir,\n })\n } else {\n buildDebug(`Building studio`)\n await buildStudio({\n autoUpdatesEnabled,\n cliConfig,\n flags,\n outDir: this.args.outputDir,\n output,\n workDir,\n })\n }\n }\n}\n"],"names":["Args","Flags","SanityCommand","buildApp","buildDebug","buildStudio","shouldAutoUpdate","determineIsApp","BuildCommand","args","outputDir","directory","description","examples","flags","boolean","allowNo","minify","default","stats","yes","char","run","cliConfig","getCliConfig","parse","isApp","workDir","getProjectRoot","output","autoUpdatesEnabled","outDir"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,aAAa,QAAO,mBAAkB;AAE9C,SAAQC,QAAQ,QAAO,+BAA8B;AACrD,SAAQC,UAAU,QAAO,iCAAgC;AACzD,SAAQC,WAAW,QAAO,kCAAiC;AAC3D,SAAQC,gBAAgB,QAAO,uCAAsC;AACrE,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,qBAAqBN;IAChC,OAAgBO,OAAO;QACrBC,WAAWV,KAAKW,SAAS,CAAC;YAACC,aAAa;QAAkB;IAC5D,EAAC;IAED,OAAgBA,cAAc,8DAA6D;IAE3F,OAAgBC,WAAW;QACzB;QACA;KACD,CAAA;IAED,OAAgBC,QAAQ;QACtB,gBAAgBb,MAAMc,OAAO,CAAC;YAC5BC,SAAS;YACTJ,aAAa;QACf;QACAK,QAAQhB,MAAMc,OAAO,CAAC;YACpBC,SAAS;YACTE,SAAS;YACTN,aAAa;QACf;QACA,eAAeX,MAAMc,OAAO,CAAC;YAC3BC,SAAS;YACTE,SAAS;YACTN,aAAa;QACf;QACAO,OAAOlB,MAAMc,OAAO,CAAC;YACnBG,SAAS;YACTN,aAAa;QACf;QACAQ,KAAKnB,MAAMc,OAAO,CAAC;YACjBM,MAAM;YACNH,SAAS;YACTN,aACE;QACJ;IACF,EAAC;IAED,MAAaU,MAAqB;QAChC,MAAMC,YAAY,MAAM,IAAI,CAACC,YAAY;QAEzC,MAAM,EAACV,KAAK,EAAC,GAAG,MAAM,IAAI,CAACW,KAAK,CAACjB;QAEjC,MAAMkB,QAAQnB,eAAegB;QAE7B,MAAMI,UAAU,AAAC,CAAA,MAAM,IAAI,CAACC,cAAc,EAAC,EAAGjB,SAAS;QAEvD,MAAMkB,SAAS,IAAI,CAACA,MAAM;QAE1B,MAAMC,qBAAqBxB,iBAAiB;YAACiB;YAAWT;YAAOe;QAAM;QAErE,IAAIH,OAAO;YACTtB,WAAW,CAAC,YAAY,CAAC;YACzB,MAAMD,SAAS;gBACb2B;gBACAP;gBACAT;gBACAiB,QAAQ,IAAI,CAACtB,IAAI,CAACC,SAAS;gBAC3BmB;gBACAF;YACF;QACF,OAAO;YACLvB,WAAW,CAAC,eAAe,CAAC;YAC5B,MAAMC,YAAY;gBAChByB;gBACAP;gBACAT;gBACAiB,QAAQ,IAAI,CAACtB,IAAI,CAACC,SAAS;gBAC3BmB;gBACAF;YACF;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/commands/build.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\n\nimport {buildApp} from '../actions/build/buildApp.js'\nimport {buildDebug} from '../actions/build/buildDebug.js'\nimport {buildStudio} from '../actions/build/buildStudio.js'\nimport {shouldAutoUpdate} from '../actions/build/shouldAutoUpdate.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class BuildCommand extends SanityCommand<typeof BuildCommand> {\n static override args = {\n outputDir: Args.directory({description: 'Output directory'}),\n }\n\n static override description = 'Build Sanity Studio into a static bundle'\n\n static override examples = [\n '<%= config.bin %> <%= command.id %>',\n '<%= config.bin %> <%= command.id %> --no-minify --source-maps',\n ]\n\n static override flags = {\n 'auto-updates': Flags.boolean({\n allowNo: true,\n description: 'Enable/disable auto updates of studio versions',\n }),\n minify: Flags.boolean({\n allowNo: true,\n default: true,\n description: 'Enable/disable minifying of built bundles',\n }),\n 'source-maps': Flags.boolean({\n allowNo: true,\n default: false,\n description: 'Enable source maps for built bundles (increases size of bundle)',\n }),\n stats: Flags.boolean({\n default: false,\n description: 'Show stats about the built bundles',\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 cliConfig = await this.getCliConfig()\n\n const {flags} = await this.parse(BuildCommand)\n\n const isApp = determineIsApp(cliConfig)\n\n const workDir = (await this.getProjectRoot()).directory\n\n const output = this.output\n\n const autoUpdatesEnabled = shouldAutoUpdate({cliConfig, flags, output})\n\n if (isApp) {\n buildDebug(`Building app`)\n await buildApp({\n autoUpdatesEnabled,\n cliConfig,\n flags,\n outDir: this.args.outputDir,\n output,\n workDir,\n })\n } else {\n buildDebug(`Building studio`)\n await buildStudio({\n autoUpdatesEnabled,\n cliConfig,\n flags,\n outDir: this.args.outputDir,\n output,\n workDir,\n })\n }\n }\n}\n"],"names":["Args","Flags","SanityCommand","buildApp","buildDebug","buildStudio","shouldAutoUpdate","determineIsApp","BuildCommand","args","outputDir","directory","description","examples","flags","boolean","allowNo","minify","default","stats","yes","char","run","cliConfig","getCliConfig","parse","isApp","workDir","getProjectRoot","output","autoUpdatesEnabled","outDir"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,aAAa,QAAO,mBAAkB;AAE9C,SAAQC,QAAQ,QAAO,+BAA8B;AACrD,SAAQC,UAAU,QAAO,iCAAgC;AACzD,SAAQC,WAAW,QAAO,kCAAiC;AAC3D,SAAQC,gBAAgB,QAAO,uCAAsC;AACrE,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,qBAAqBN;IAChC,OAAgBO,OAAO;QACrBC,WAAWV,KAAKW,SAAS,CAAC;YAACC,aAAa;QAAkB;IAC5D,EAAC;IAED,OAAgBA,cAAc,2CAA0C;IAExE,OAAgBC,WAAW;QACzB;QACA;KACD,CAAA;IAED,OAAgBC,QAAQ;QACtB,gBAAgBb,MAAMc,OAAO,CAAC;YAC5BC,SAAS;YACTJ,aAAa;QACf;QACAK,QAAQhB,MAAMc,OAAO,CAAC;YACpBC,SAAS;YACTE,SAAS;YACTN,aAAa;QACf;QACA,eAAeX,MAAMc,OAAO,CAAC;YAC3BC,SAAS;YACTE,SAAS;YACTN,aAAa;QACf;QACAO,OAAOlB,MAAMc,OAAO,CAAC;YACnBG,SAAS;YACTN,aAAa;QACf;QACAQ,KAAKnB,MAAMc,OAAO,CAAC;YACjBM,MAAM;YACNH,SAAS;YACTN,aACE;QACJ;IACF,EAAC;IAED,MAAaU,MAAqB;QAChC,MAAMC,YAAY,MAAM,IAAI,CAACC,YAAY;QAEzC,MAAM,EAACV,KAAK,EAAC,GAAG,MAAM,IAAI,CAACW,KAAK,CAACjB;QAEjC,MAAMkB,QAAQnB,eAAegB;QAE7B,MAAMI,UAAU,AAAC,CAAA,MAAM,IAAI,CAACC,cAAc,EAAC,EAAGjB,SAAS;QAEvD,MAAMkB,SAAS,IAAI,CAACA,MAAM;QAE1B,MAAMC,qBAAqBxB,iBAAiB;YAACiB;YAAWT;YAAOe;QAAM;QAErE,IAAIH,OAAO;YACTtB,WAAW,CAAC,YAAY,CAAC;YACzB,MAAMD,SAAS;gBACb2B;gBACAP;gBACAT;gBACAiB,QAAQ,IAAI,CAACtB,IAAI,CAACC,SAAS;gBAC3BmB;gBACAF;YACF;QACF,OAAO;YACLvB,WAAW,CAAC,eAAe,CAAC;YAC5B,MAAMC,YAAY;gBAChByB;gBACAP;gBACAT;gBACAiB,QAAQ,IAAI,CAACtB,IAAI,CAACC,SAAS;gBAC3BmB;gBACAF;YACF;QACF;IACF;AACF"}
@@ -17,7 +17,7 @@ export class Add extends SanityCommand {
17
17
  required: true
18
18
  })
19
19
  };
20
- static description = 'Allow a new origin to use your project API through CORS';
20
+ static description = 'Add a CORS origin to the project';
21
21
  static examples = [
22
22
  {
23
23
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/cors/add.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\nimport {oneline} from 'oneline'\n\nimport {filterAndValidateOrigin} from '../../actions/cors/filterAndValidateOrigin.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createCorsOrigin} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst addCorsDebug = subdebug('cors:add')\n\nexport class Add extends SanityCommand<typeof Add> {\n static override args = {\n origin: Args.string({\n description: 'Origin to allow (e.g., https://example.com)',\n required: true,\n }),\n }\n\n static override description = 'Allow a new origin to use your project API through CORS'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively add a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials',\n description: 'Add a localhost origin without credentials',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --credentials',\n description: 'Add a production origin with credentials allowed',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123',\n description: 'Add a CORS origin for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to add CORS origin to',\n semantics: 'override',\n }),\n credentials: Flags.boolean({\n allowNo: true,\n default: undefined,\n description: 'Allow credentials (token/cookie) to be sent from this origin',\n required: false,\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(Add)\n const {origin} = args\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'create', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Check if the origin argument looks like a file path and warn\n try {\n const isFile = fs.existsSync(path.join(process.cwd(), args.origin))\n if (isFile) {\n this.warn(`Origin \"${args.origin}?\" Remember to quote values (sanity cors add \"*\")`)\n }\n } catch {\n // Ignore errors checking if it's a file\n }\n\n const filteredOrigin = await filterAndValidateOrigin(origin, this.output)\n const hasWildcard = origin.includes('*')\n\n if (hasWildcard) {\n const confirmed = await this.promptForWildcardConfirmation(origin)\n if (!confirmed) {\n this.error('Operation cancelled', {exit: 1})\n }\n }\n\n const allowCredentials =\n flags.credentials === undefined\n ? await this.promptForCredentials(hasWildcard)\n : Boolean(flags.credentials)\n\n if (filteredOrigin !== origin) {\n this.log(`Normalized origin to: ${filteredOrigin}`)\n }\n\n try {\n const response = await createCorsOrigin({\n allowCredentials,\n origin: filteredOrigin,\n projectId,\n })\n\n addCorsDebug(`CORS origin added successfully`, response)\n\n this.log('CORS origin added successfully')\n } catch (error) {\n const err = error as Error\n\n addCorsDebug(`Error adding CORS origin`, err)\n this.error(`CORS origin addition failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n /**\n * Prompt the user for credentials\n *\n * @param hasWildcard - Whether the origin contains a wildcard\n * @returns - Whether to allow credentials\n */\n private async promptForCredentials(hasWildcard: boolean) {\n this.log('')\n if (hasWildcard) {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n We ${styleText(['red', 'underline'], 'HIGHLY')} recommend NOT allowing credentials\n on origins containing wildcards. If you are logged in to a studio, people will\n be able to send requests ${styleText('underline', 'on your behalf')} to read and modify\n data, from any matching origin. Please tread carefully!\n `)\n } else {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n Should this origin be allowed to send requests using authentication tokens or\n session cookies? Be aware that any script on this origin will be able to send\n requests ${styleText('underline', 'on your behalf')} to read and modify data if you\n are logged in to a Sanity studio. If this origin hosts a studio, you will need\n this, otherwise you should probably answer \"No\" (n).\n `)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Allow credentials to be sent from this origin? Please read the warning above.\n `,\n })\n }\n\n /**\n * Prompt the user for wildcard confirmation\n *\n * @param origin - The origin to check for wildcards\n * @returns - Whether to allow the origin\n */\n private async promptForWildcardConfirmation(origin: string) {\n this.log('')\n this.log(styleText('yellow', `${logSymbols.warning} Warning: Examples of allowed origins:`))\n\n if (origin === '*') {\n this.log('- http://www.some-malicious.site')\n this.log('- https://not.what-you-were-expecting.com')\n this.log('- https://high-traffic-site.com')\n this.log('- http://192.168.1.1:8080')\n } else {\n this.log(`- ${origin.replace(/:\\*/, ':1234').replaceAll('*', 'foo')}`)\n this.log(`- ${origin.replace(/:\\*/, ':3030').replaceAll('*', 'foo.bar')}`)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Using wildcards can be ${styleText('red', 'risky')}.\n Are you ${styleText('underline', 'absolutely sure')} you want to allow this origin?`,\n })\n }\n}\n"],"names":["fs","path","styleText","Args","Flags","SanityCommand","subdebug","confirm","logSymbols","oneline","filterAndValidateOrigin","promptForProject","createCorsOrigin","getProjectIdFlag","addCorsDebug","Add","args","origin","string","description","required","examples","command","flags","semantics","credentials","boolean","allowNo","default","undefined","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","isFile","existsSync","join","process","cwd","warn","filteredOrigin","output","hasWildcard","includes","confirmed","promptForWildcardConfirmation","error","exit","allowCredentials","promptForCredentials","Boolean","log","response","err","message","warning","replace","replaceAll"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/cors/add.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\nimport {oneline} from 'oneline'\n\nimport {filterAndValidateOrigin} from '../../actions/cors/filterAndValidateOrigin.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createCorsOrigin} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst addCorsDebug = subdebug('cors:add')\n\nexport class Add extends SanityCommand<typeof Add> {\n static override args = {\n origin: Args.string({\n description: 'Origin to allow (e.g., https://example.com)',\n required: true,\n }),\n }\n\n static override description = 'Add a CORS origin to the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively add a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> http://localhost:3000 --no-credentials',\n description: 'Add a localhost origin without credentials',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --credentials',\n description: 'Add a production origin with credentials allowed',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://myapp.com --project-id abc123',\n description: 'Add a CORS origin for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to add CORS origin to',\n semantics: 'override',\n }),\n credentials: Flags.boolean({\n allowNo: true,\n default: undefined,\n description: 'Allow credentials (token/cookie) to be sent from this origin',\n required: false,\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(Add)\n const {origin} = args\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'create', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Check if the origin argument looks like a file path and warn\n try {\n const isFile = fs.existsSync(path.join(process.cwd(), args.origin))\n if (isFile) {\n this.warn(`Origin \"${args.origin}?\" Remember to quote values (sanity cors add \"*\")`)\n }\n } catch {\n // Ignore errors checking if it's a file\n }\n\n const filteredOrigin = await filterAndValidateOrigin(origin, this.output)\n const hasWildcard = origin.includes('*')\n\n if (hasWildcard) {\n const confirmed = await this.promptForWildcardConfirmation(origin)\n if (!confirmed) {\n this.error('Operation cancelled', {exit: 1})\n }\n }\n\n const allowCredentials =\n flags.credentials === undefined\n ? await this.promptForCredentials(hasWildcard)\n : Boolean(flags.credentials)\n\n if (filteredOrigin !== origin) {\n this.log(`Normalized origin to: ${filteredOrigin}`)\n }\n\n try {\n const response = await createCorsOrigin({\n allowCredentials,\n origin: filteredOrigin,\n projectId,\n })\n\n addCorsDebug(`CORS origin added successfully`, response)\n\n this.log('CORS origin added successfully')\n } catch (error) {\n const err = error as Error\n\n addCorsDebug(`Error adding CORS origin`, err)\n this.error(`CORS origin addition failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n /**\n * Prompt the user for credentials\n *\n * @param hasWildcard - Whether the origin contains a wildcard\n * @returns - Whether to allow credentials\n */\n private async promptForCredentials(hasWildcard: boolean) {\n this.log('')\n if (hasWildcard) {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n We ${styleText(['red', 'underline'], 'HIGHLY')} recommend NOT allowing credentials\n on origins containing wildcards. If you are logged in to a studio, people will\n be able to send requests ${styleText('underline', 'on your behalf')} to read and modify\n data, from any matching origin. Please tread carefully!\n `)\n } else {\n this.log(oneline`\n ${styleText('yellow', `${logSymbols.warning} Warning:`)}\n Should this origin be allowed to send requests using authentication tokens or\n session cookies? Be aware that any script on this origin will be able to send\n requests ${styleText('underline', 'on your behalf')} to read and modify data if you\n are logged in to a Sanity studio. If this origin hosts a studio, you will need\n this, otherwise you should probably answer \"No\" (n).\n `)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Allow credentials to be sent from this origin? Please read the warning above.\n `,\n })\n }\n\n /**\n * Prompt the user for wildcard confirmation\n *\n * @param origin - The origin to check for wildcards\n * @returns - Whether to allow the origin\n */\n private async promptForWildcardConfirmation(origin: string) {\n this.log('')\n this.log(styleText('yellow', `${logSymbols.warning} Warning: Examples of allowed origins:`))\n\n if (origin === '*') {\n this.log('- http://www.some-malicious.site')\n this.log('- https://not.what-you-were-expecting.com')\n this.log('- https://high-traffic-site.com')\n this.log('- http://192.168.1.1:8080')\n } else {\n this.log(`- ${origin.replace(/:\\*/, ':1234').replaceAll('*', 'foo')}`)\n this.log(`- ${origin.replace(/:\\*/, ':3030').replaceAll('*', 'foo.bar')}`)\n }\n\n this.log('')\n\n return confirm({\n default: false,\n message: oneline`\n Using wildcards can be ${styleText('red', 'risky')}.\n Are you ${styleText('underline', 'absolutely sure')} you want to allow this origin?`,\n })\n }\n}\n"],"names":["fs","path","styleText","Args","Flags","SanityCommand","subdebug","confirm","logSymbols","oneline","filterAndValidateOrigin","promptForProject","createCorsOrigin","getProjectIdFlag","addCorsDebug","Add","args","origin","string","description","required","examples","command","flags","semantics","credentials","boolean","allowNo","default","undefined","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","isFile","existsSync","join","process","cwd","warn","filteredOrigin","output","hasWildcard","includes","confirmed","promptForWildcardConfirmation","error","exit","allowCredentials","promptForCredentials","Boolean","log","response","err","message","warning","replace","replaceAll"],"mappings":"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"}
@@ -12,7 +12,7 @@ export class Delete extends SanityCommand {
12
12
  required: false
13
13
  })
14
14
  };
15
- static description = 'Delete an existing CORS origin from your project';
15
+ static description = 'Delete a CORS origin from the project';
16
16
  static examples = [
17
17
  {
18
18
  command: '<%= config.bin %> <%= command.id %>',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/cors/delete.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, deleteCorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deleteCorsDebug = subdebug('cors:delete')\n\nexport class Delete extends SanityCommand<typeof Delete> {\n static override args = {\n origin: Args.string({\n description: 'Origin to delete (will prompt if not provided)',\n required: false,\n }),\n }\n\n static override description = 'Delete an existing CORS origin from your project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively select and delete a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://example.com',\n description: 'Delete a specific CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'Delete a CORS origin from a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete CORS origin from',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n const {args} = await this.parse(Delete)\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'delete', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Get the origin ID to delete\n const originId = await this.promptForOrigin(args.origin, projectId)\n\n try {\n await deleteCorsOrigin({originId, projectId})\n\n this.log('Origin deleted')\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error deleting CORS origin ${originId} for project ${projectId}`, err)\n this.error(`Origin deletion failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n private async promptForOrigin(\n specifiedOrigin: string | undefined,\n projectId: string,\n ): Promise<number> {\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`Failed to fetch CORS origins:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.error('No CORS origins configured for this project.', {exit: 1})\n }\n\n // If origin is specified, find it in the list\n if (specifiedOrigin) {\n const specifiedOriginLower = specifiedOrigin.toLowerCase()\n const selectedOrigin = origins.find(\n (origin) => origin.origin.toLowerCase() === specifiedOriginLower,\n )\n\n if (!selectedOrigin) {\n this.error(`Origin \"${specifiedOrigin}\" not found`, {exit: 1})\n }\n\n return selectedOrigin.id\n }\n\n // If no origin specified, prompt user to select one\n const choices = origins.map((origin) => ({\n name: origin.origin,\n value: origin.id,\n }))\n\n const selectedId = await select({\n choices,\n message: 'Select origin to delete',\n })\n\n return selectedId\n }\n}\n"],"names":["Args","SanityCommand","subdebug","select","promptForProject","deleteCorsOrigin","listCorsOrigins","getProjectIdFlag","deleteCorsDebug","Delete","args","origin","string","description","required","examples","command","flags","semantics","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","originId","promptForOrigin","log","error","err","message","exit","specifiedOrigin","origins","length","specifiedOriginLower","toLowerCase","selectedOrigin","find","id","choices","map","name","value","selectedId"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,MAAM,QAAO,sBAAqB;AAE1C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAyBC,gBAAgB,EAAEC,eAAe,QAAO,yBAAwB;AACzF,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,kBAAkBN,SAAS;AAEjC,OAAO,MAAMO,eAAeR;IAC1B,OAAgBS,OAAO;QACrBC,QAAQX,KAAKY,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,mDAAkD;IAEhF,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGV,iBAAiB;YAClBM,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAC;IAED,MAAaC,MAAqB;QAChC,MAAM,EAACT,IAAI,EAAC,GAAG,MAAM,IAAI,CAACU,KAAK,CAACX;QAEhC,iCAAiC;QACjC,MAAMY,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAUC,YAAY;wBAAqB;qBAAE;gBAC7E;QACJ;QAEA,8BAA8B;QAC9B,MAAMC,WAAW,MAAM,IAAI,CAACC,eAAe,CAAClB,KAAKC,MAAM,EAAEU;QAEzD,IAAI;YACF,MAAMhB,iBAAiB;gBAACsB;gBAAUN;YAAS;YAE3C,IAAI,CAACQ,GAAG,CAAC;QACX,EAAE,OAAOC,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,2BAA2B,EAAEmB,SAAS,aAAa,EAAEN,WAAW,EAAEU;YACnF,IAAI,CAACD,KAAK,CAAC,CAAC,yBAAyB,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QAChE;IACF;IAEA,MAAcL,gBACZM,eAAmC,EACnCb,SAAiB,EACA;QACjB,IAAIc;QACJ,IAAI;YACFA,UAAU,MAAM7B,gBAAgBe;QAClC,EAAE,OAAOS,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,wCAAwC,EAAEa,WAAW,EAAEU;YACxE,IAAI,CAACD,KAAK,CAAC,CAAC,+BAA+B,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QACtE;QAEA,IAAIE,QAAQC,MAAM,KAAK,GAAG;YACxB,IAAI,CAACN,KAAK,CAAC,gDAAgD;gBAACG,MAAM;YAAC;QACrE;QAEA,8CAA8C;QAC9C,IAAIC,iBAAiB;YACnB,MAAMG,uBAAuBH,gBAAgBI,WAAW;YACxD,MAAMC,iBAAiBJ,QAAQK,IAAI,CACjC,CAAC7B,SAAWA,OAAOA,MAAM,CAAC2B,WAAW,OAAOD;YAG9C,IAAI,CAACE,gBAAgB;gBACnB,IAAI,CAACT,KAAK,CAAC,CAAC,QAAQ,EAAEI,gBAAgB,WAAW,CAAC,EAAE;oBAACD,MAAM;gBAAC;YAC9D;YAEA,OAAOM,eAAeE,EAAE;QAC1B;QAEA,oDAAoD;QACpD,MAAMC,UAAUP,QAAQQ,GAAG,CAAC,CAAChC,SAAY,CAAA;gBACvCiC,MAAMjC,OAAOA,MAAM;gBACnBkC,OAAOlC,OAAO8B,EAAE;YAClB,CAAA;QAEA,MAAMK,aAAa,MAAM3C,OAAO;YAC9BuC;YACAV,SAAS;QACX;QAEA,OAAOc;IACT;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/cors/delete.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, deleteCorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deleteCorsDebug = subdebug('cors:delete')\n\nexport class Delete extends SanityCommand<typeof Delete> {\n static override args = {\n origin: Args.string({\n description: 'Origin to delete (will prompt if not provided)',\n required: false,\n }),\n }\n\n static override description = 'Delete a CORS origin from the project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively select and delete a CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> https://example.com',\n description: 'Delete a specific CORS origin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'Delete a CORS origin from a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to delete CORS origin from',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n const {args} = await this.parse(Delete)\n\n // Ensure we have project context\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'delete', permission: 'sanity.project.cors'}],\n }),\n })\n\n // Get the origin ID to delete\n const originId = await this.promptForOrigin(args.origin, projectId)\n\n try {\n await deleteCorsOrigin({originId, projectId})\n\n this.log('Origin deleted')\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error deleting CORS origin ${originId} for project ${projectId}`, err)\n this.error(`Origin deletion failed:\\n${err.message}`, {exit: 1})\n }\n }\n\n private async promptForOrigin(\n specifiedOrigin: string | undefined,\n projectId: string,\n ): Promise<number> {\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n deleteCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`Failed to fetch CORS origins:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.error('No CORS origins configured for this project.', {exit: 1})\n }\n\n // If origin is specified, find it in the list\n if (specifiedOrigin) {\n const specifiedOriginLower = specifiedOrigin.toLowerCase()\n const selectedOrigin = origins.find(\n (origin) => origin.origin.toLowerCase() === specifiedOriginLower,\n )\n\n if (!selectedOrigin) {\n this.error(`Origin \"${specifiedOrigin}\" not found`, {exit: 1})\n }\n\n return selectedOrigin.id\n }\n\n // If no origin specified, prompt user to select one\n const choices = origins.map((origin) => ({\n name: origin.origin,\n value: origin.id,\n }))\n\n const selectedId = await select({\n choices,\n message: 'Select origin to delete',\n })\n\n return selectedId\n }\n}\n"],"names":["Args","SanityCommand","subdebug","select","promptForProject","deleteCorsOrigin","listCorsOrigins","getProjectIdFlag","deleteCorsDebug","Delete","args","origin","string","description","required","examples","command","flags","semantics","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","originId","promptForOrigin","log","error","err","message","exit","specifiedOrigin","origins","length","specifiedOriginLower","toLowerCase","selectedOrigin","find","id","choices","map","name","value","selectedId"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,MAAM,QAAO,sBAAqB;AAE1C,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAyBC,gBAAgB,EAAEC,eAAe,QAAO,yBAAwB;AACzF,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,kBAAkBN,SAAS;AAEjC,OAAO,MAAMO,eAAeR;IAC1B,OAAgBS,OAAO;QACrBC,QAAQX,KAAKY,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,wCAAuC;IAErE,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGV,iBAAiB;YAClBM,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAC;IAED,MAAaC,MAAqB;QAChC,MAAM,EAACT,IAAI,EAAC,GAAG,MAAM,IAAI,CAACU,KAAK,CAACX;QAEhC,iCAAiC;QACjC,MAAMY,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRnB,iBAAiB;oBACfoB,qBAAqB;wBAAC;4BAACC,OAAO;4BAAUC,YAAY;wBAAqB;qBAAE;gBAC7E;QACJ;QAEA,8BAA8B;QAC9B,MAAMC,WAAW,MAAM,IAAI,CAACC,eAAe,CAAClB,KAAKC,MAAM,EAAEU;QAEzD,IAAI;YACF,MAAMhB,iBAAiB;gBAACsB;gBAAUN;YAAS;YAE3C,IAAI,CAACQ,GAAG,CAAC;QACX,EAAE,OAAOC,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,2BAA2B,EAAEmB,SAAS,aAAa,EAAEN,WAAW,EAAEU;YACnF,IAAI,CAACD,KAAK,CAAC,CAAC,yBAAyB,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QAChE;IACF;IAEA,MAAcL,gBACZM,eAAmC,EACnCb,SAAiB,EACA;QACjB,IAAIc;QACJ,IAAI;YACFA,UAAU,MAAM7B,gBAAgBe;QAClC,EAAE,OAAOS,OAAO;YACd,MAAMC,MAAMD;YACZtB,gBAAgB,CAAC,wCAAwC,EAAEa,WAAW,EAAEU;YACxE,IAAI,CAACD,KAAK,CAAC,CAAC,+BAA+B,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QACtE;QAEA,IAAIE,QAAQC,MAAM,KAAK,GAAG;YACxB,IAAI,CAACN,KAAK,CAAC,gDAAgD;gBAACG,MAAM;YAAC;QACrE;QAEA,8CAA8C;QAC9C,IAAIC,iBAAiB;YACnB,MAAMG,uBAAuBH,gBAAgBI,WAAW;YACxD,MAAMC,iBAAiBJ,QAAQK,IAAI,CACjC,CAAC7B,SAAWA,OAAOA,MAAM,CAAC2B,WAAW,OAAOD;YAG9C,IAAI,CAACE,gBAAgB;gBACnB,IAAI,CAACT,KAAK,CAAC,CAAC,QAAQ,EAAEI,gBAAgB,WAAW,CAAC,EAAE;oBAACD,MAAM;gBAAC;YAC9D;YAEA,OAAOM,eAAeE,EAAE;QAC1B;QAEA,oDAAoD;QACpD,MAAMC,UAAUP,QAAQQ,GAAG,CAAC,CAAChC,SAAY,CAAA;gBACvCiC,MAAMjC,OAAOA,MAAM;gBACnBkC,OAAOlC,OAAO8B,EAAE;YAClB,CAAA;QAEA,MAAMK,aAAa,MAAM3C,OAAO;YAC9BuC;YACAV,SAAS;QACX;QAEA,OAAOc;IACT;AACF"}
@@ -4,11 +4,11 @@ import { listCorsOrigins } from '../../services/cors.js';
4
4
  import { getProjectIdFlag } from '../../util/sharedFlags.js';
5
5
  const listCorsDebug = subdebug('cors:list');
6
6
  export class List extends SanityCommand {
7
- static description = 'List all origins allowed to access the API for this project';
7
+ static description = 'List CORS origins for the project';
8
8
  static examples = [
9
9
  {
10
10
  command: '<%= config.bin %> <%= command.id %>',
11
- description: 'List CORS origins for the current project'
11
+ description: 'List CORS origins for the project'
12
12
  },
13
13
  {
14
14
  command: '<%= config.bin %> <%= command.id %> --project-id abc123',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/cors/list.ts"],"sourcesContent":["import {SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listCorsDebug = subdebug('cors:list')\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List all origins allowed to access the API for this project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List CORS origins for the current project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List CORS origins for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list CORS origins for',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n await this.parse(List)\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.cors'}],\n }),\n })\n\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n\n listCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`CORS origins list retrieval failed:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.log('No CORS origins configured for this project.')\n return\n }\n\n // Output each origin on a new line, matching the original behavior\n this.log(origins.map((origin) => origin.origin).join('\\n'))\n }\n}\n"],"names":["SanityCommand","subdebug","promptForProject","listCorsOrigins","getProjectIdFlag","listCorsDebug","List","description","examples","command","flags","semantics","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","origins","error","err","message","exit","length","log","map","origin","join"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AAExD,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAyBC,eAAe,QAAO,yBAAwB;AACvE,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,gBAAgBJ,SAAS;AAE/B,OAAO,MAAMK,aAAaN;IACxB,OAAgBO,cAAc,8DAA6D;IAC3F,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;IACJ,EAAC;IAED,MAAaC,MAAqB;QAChC,MAAM,IAAI,CAACC,KAAK,CAACP;QAEjB,MAAMQ,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRd,iBAAiB;oBACfe,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAqB;qBAAE;gBAC3E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,UAAU,MAAMjB,gBAAgBW;QAClC,EAAE,OAAOO,OAAO;YACd,MAAMC,MAAMD;YAEZhB,cAAc,CAAC,wCAAwC,EAAES,WAAW,EAAEQ;YACtE,IAAI,CAACD,KAAK,CAAC,CAAC,qCAAqC,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QAC5E;QAEA,IAAIJ,QAAQK,MAAM,KAAK,GAAG;YACxB,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,mEAAmE;QACnE,IAAI,CAACA,GAAG,CAACN,QAAQO,GAAG,CAAC,CAACC,SAAWA,OAAOA,MAAM,EAAEC,IAAI,CAAC;IACvD;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/cors/list.ts"],"sourcesContent":["import {SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type CorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listCorsDebug = subdebug('cors:list')\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List CORS origins for the project'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List CORS origins for the project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123',\n description: 'List CORS origins for a specific project',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list CORS origins for',\n semantics: 'override',\n }),\n }\n\n public async run(): Promise<void> {\n await this.parse(List)\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.cors'}],\n }),\n })\n\n let origins: CorsOrigin[]\n try {\n origins = await listCorsOrigins(projectId)\n } catch (error) {\n const err = error as Error\n\n listCorsDebug(`Error fetching CORS origins for project ${projectId}`, err)\n this.error(`CORS origins list retrieval failed:\\n${err.message}`, {exit: 1})\n }\n\n if (origins.length === 0) {\n this.log('No CORS origins configured for this project.')\n return\n }\n\n // Output each origin on a new line, matching the original behavior\n this.log(origins.map((origin) => origin.origin).join('\\n'))\n }\n}\n"],"names":["SanityCommand","subdebug","promptForProject","listCorsOrigins","getProjectIdFlag","listCorsDebug","List","description","examples","command","flags","semantics","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","origins","error","err","message","exit","length","log","map","origin","join"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AAExD,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAyBC,eAAe,QAAO,yBAAwB;AACvE,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,gBAAgBJ,SAAS;AAE/B,OAAO,MAAMK,aAAaN;IACxB,OAAgBO,cAAc,oCAAmC;IACjE,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtB,GAAGN,iBAAiB;YAClBG,aAAa;YACbI,WAAW;QACb,EAAE;IACJ,EAAC;IAED,MAAaC,MAAqB;QAChC,MAAM,IAAI,CAACC,KAAK,CAACP;QAEjB,MAAMQ,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACRd,iBAAiB;oBACfe,qBAAqB;wBAAC;4BAACC,OAAO;4BAAQC,YAAY;wBAAqB;qBAAE;gBAC3E;QACJ;QAEA,IAAIC;QACJ,IAAI;YACFA,UAAU,MAAMjB,gBAAgBW;QAClC,EAAE,OAAOO,OAAO;YACd,MAAMC,MAAMD;YAEZhB,cAAc,CAAC,wCAAwC,EAAES,WAAW,EAAEQ;YACtE,IAAI,CAACD,KAAK,CAAC,CAAC,qCAAqC,EAAEC,IAAIC,OAAO,EAAE,EAAE;gBAACC,MAAM;YAAC;QAC5E;QAEA,IAAIJ,QAAQK,MAAM,KAAK,GAAG;YACxB,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,mEAAmE;QACnE,IAAI,CAACA,GAAG,CAACN,QAAQO,GAAG,CAAC,CAACC,SAAWA,OAAOA,MAAM,EAAEC,IAAI,CAAC;IACvD;AACF"}