@sanity/cli 6.0.0-alpha.9 → 6.1.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 (613) hide show
  1. package/README.md +602 -291
  2. package/bin/run.js +2 -0
  3. package/dist/SanityHelp.js +51 -23
  4. package/dist/SanityHelp.js.map +1 -1
  5. package/dist/actions/auth/authServer.js +28 -22
  6. package/dist/actions/auth/authServer.js.map +1 -1
  7. package/dist/actions/auth/login/getProvider.js +49 -38
  8. package/dist/actions/auth/login/getProvider.js.map +1 -1
  9. package/dist/actions/auth/login/getSSOProvider.js +25 -19
  10. package/dist/actions/auth/login/getSSOProvider.js.map +1 -1
  11. package/dist/actions/auth/login/login.js +12 -33
  12. package/dist/actions/auth/login/login.js.map +1 -1
  13. package/dist/actions/auth/types.js.map +1 -1
  14. package/dist/actions/backup/downloadAsset.js +9 -9
  15. package/dist/actions/backup/downloadAsset.js.map +1 -1
  16. package/dist/actions/backup/downloadDocument.js +8 -8
  17. package/dist/actions/backup/downloadDocument.js.map +1 -1
  18. package/dist/actions/build/buildApp.js +55 -18
  19. package/dist/actions/build/buildApp.js.map +1 -1
  20. package/dist/actions/build/buildStaticFiles.js +3 -2
  21. package/dist/actions/build/buildStaticFiles.js.map +1 -1
  22. package/dist/actions/build/buildStudio.js +72 -44
  23. package/dist/actions/build/buildStudio.js.map +1 -1
  24. package/dist/actions/build/buildVendorDependencies.js +18 -52
  25. package/dist/actions/build/buildVendorDependencies.js.map +1 -1
  26. package/dist/actions/build/checkRequiredDependencies.js +13 -8
  27. package/dist/actions/build/checkRequiredDependencies.js.map +1 -1
  28. package/dist/actions/build/checkStudioDependencyVersions.js +19 -17
  29. package/dist/actions/build/checkStudioDependencyVersions.js.map +1 -1
  30. package/dist/actions/build/createExternalFromImportMap.js +1 -1
  31. package/dist/actions/build/createExternalFromImportMap.js.map +1 -1
  32. package/dist/actions/build/determineBasePath.js +5 -2
  33. package/dist/actions/build/determineBasePath.js.map +1 -1
  34. package/dist/actions/build/getViteConfig.js +47 -4
  35. package/dist/actions/build/getViteConfig.js.map +1 -1
  36. package/dist/actions/build/handlePrereleaseVersions.js +44 -0
  37. package/dist/actions/build/handlePrereleaseVersions.js.map +1 -0
  38. package/dist/actions/build/renderDocument.js +6 -10
  39. package/dist/actions/build/renderDocument.js.map +1 -1
  40. package/dist/actions/build/renderDocumentWorker/components/BasicDocument.js +4 -4
  41. package/dist/actions/build/renderDocumentWorker/components/BasicDocument.js.map +1 -1
  42. package/dist/actions/build/renderDocumentWorker/components/DefaultDocument.js +3 -3
  43. package/dist/actions/build/renderDocumentWorker/components/DefaultDocument.js.map +1 -1
  44. package/dist/actions/build/renderDocumentWorker/components/GlobalErrorHandler.js +1 -0
  45. package/dist/actions/build/renderDocumentWorker/components/GlobalErrorHandler.js.map +1 -1
  46. package/dist/actions/build/renderDocumentWorker/getDocumentComponent.js +2 -2
  47. package/dist/actions/build/renderDocumentWorker/getDocumentComponent.js.map +1 -1
  48. package/dist/actions/build/renderDocumentWorker/renderDocumentWorker.js +1 -1
  49. package/dist/actions/build/renderDocumentWorker/renderDocumentWorker.js.map +1 -1
  50. package/dist/actions/build/shouldAutoUpdate.js +2 -0
  51. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  52. package/dist/actions/build/types.js.map +1 -1
  53. package/dist/actions/build/writeFavicons.js +3 -5
  54. package/dist/actions/build/writeFavicons.js.map +1 -1
  55. package/dist/actions/build/writeSanityRuntime.js +4 -3
  56. package/dist/actions/build/writeSanityRuntime.js.map +1 -1
  57. package/dist/actions/codemods/reactIconsV3.js +2 -2
  58. package/dist/actions/codemods/reactIconsV3.js.map +1 -1
  59. package/dist/actions/dataset/create.js +7 -1
  60. package/dist/actions/dataset/create.js.map +1 -1
  61. package/dist/actions/dataset/determineDatasetAclMode.js.map +1 -1
  62. package/dist/actions/dataset/resolveDataset.js +26 -0
  63. package/dist/actions/dataset/resolveDataset.js.map +1 -0
  64. package/dist/actions/debug/formatters.js +22 -0
  65. package/dist/actions/debug/formatters.js.map +1 -0
  66. package/dist/actions/deploy/createStudioUserApplication.js +17 -4
  67. package/dist/actions/deploy/createStudioUserApplication.js.map +1 -1
  68. package/dist/actions/deploy/deployApp.js +41 -15
  69. package/dist/actions/deploy/deployApp.js.map +1 -1
  70. package/dist/actions/deploy/deployStudio.js +92 -44
  71. package/dist/actions/deploy/deployStudio.js.map +1 -1
  72. package/dist/actions/deploy/deployStudioSchemasAndManifests.js +55 -0
  73. package/dist/actions/deploy/deployStudioSchemasAndManifests.js.map +1 -0
  74. package/dist/actions/deploy/deployStudioSchemasAndManifests.worker.js +120 -0
  75. package/dist/actions/deploy/deployStudioSchemasAndManifests.worker.js.map +1 -0
  76. package/dist/actions/deploy/findUserApplicationForStudio.js +35 -12
  77. package/dist/actions/deploy/findUserApplicationForStudio.js.map +1 -1
  78. package/dist/actions/deploy/types.js +10 -1
  79. package/dist/actions/deploy/types.js.map +1 -1
  80. package/dist/actions/deploy/urlUtils.js +21 -0
  81. package/dist/actions/deploy/urlUtils.js.map +1 -0
  82. package/dist/actions/dev/getDashboardAppUrl.js +48 -0
  83. package/dist/actions/dev/getDashboardAppUrl.js.map +1 -0
  84. package/dist/actions/dev/getDevServerConfig.js +7 -3
  85. package/dist/actions/dev/getDevServerConfig.js.map +1 -1
  86. package/dist/actions/dev/startAppDevServer.js +3 -3
  87. package/dist/actions/dev/startAppDevServer.js.map +1 -1
  88. package/dist/actions/dev/startStudioDevServer.js +14 -14
  89. package/dist/actions/dev/startStudioDevServer.js.map +1 -1
  90. package/dist/actions/doctor/checks/cliInstallation.js +56 -0
  91. package/dist/actions/doctor/checks/cliInstallation.js.map +1 -0
  92. package/dist/actions/doctor/checks/index.js +16 -0
  93. package/dist/actions/doctor/checks/index.js.map +1 -0
  94. package/dist/actions/doctor/runDoctorChecks.js +56 -0
  95. package/dist/actions/doctor/runDoctorChecks.js.map +1 -0
  96. package/dist/actions/doctor/types.js +3 -0
  97. package/dist/actions/doctor/types.js.map +1 -0
  98. package/dist/actions/documents/types.js.map +1 -1
  99. package/dist/actions/documents/validate.js +11 -2
  100. package/dist/actions/documents/validate.js.map +1 -1
  101. package/dist/actions/documents/validateDocuments.worker.js +4 -4
  102. package/dist/actions/documents/validateDocuments.worker.js.map +1 -1
  103. package/dist/actions/documents/validation/reporters/jsonReporter.js +1 -1
  104. package/dist/actions/documents/validation/reporters/jsonReporter.js.map +1 -1
  105. package/dist/actions/documents/validation/reporters/ndjsonReporter.js +1 -1
  106. package/dist/actions/documents/validation/reporters/ndjsonReporter.js.map +1 -1
  107. package/dist/actions/documents/validation/reporters/prettyReporter/formatDocumentValidation.js +1 -1
  108. package/dist/actions/documents/validation/reporters/prettyReporter/formatDocumentValidation.js.map +1 -1
  109. package/dist/actions/documents/validation/reporters/prettyReporter/tree.js +108 -0
  110. package/dist/actions/documents/validation/reporters/prettyReporter/tree.js.map +1 -0
  111. package/dist/actions/graphql/SchemaError.js +4 -26
  112. package/dist/actions/graphql/SchemaError.js.map +1 -1
  113. package/dist/actions/graphql/__tests__/fixtures/many-self-refs.js +540 -0
  114. package/dist/actions/graphql/__tests__/fixtures/many-self-refs.js.map +1 -0
  115. package/dist/actions/graphql/__tests__/fixtures/test-studio.js +1143 -0
  116. package/dist/actions/graphql/__tests__/fixtures/test-studio.js.map +1 -0
  117. package/dist/actions/graphql/__tests__/fixtures/union-refs.js +591 -0
  118. package/dist/actions/graphql/__tests__/fixtures/union-refs.js.map +1 -0
  119. package/dist/actions/graphql/__tests__/helpers.js +23 -0
  120. package/dist/actions/graphql/__tests__/helpers.js.map +1 -0
  121. package/dist/actions/graphql/extractFromSanitySchema.js +5 -5
  122. package/dist/actions/graphql/extractFromSanitySchema.js.map +1 -1
  123. package/dist/actions/graphql/extractGraphQLAPIs.js +150 -0
  124. package/dist/actions/graphql/extractGraphQLAPIs.js.map +1 -0
  125. package/dist/actions/graphql/extractGraphQLAPIs.worker.js +12 -0
  126. package/dist/actions/graphql/extractGraphQLAPIs.worker.js.map +1 -0
  127. package/dist/actions/graphql/gen1/generateTypeFilters.js +1 -1
  128. package/dist/actions/graphql/gen1/generateTypeFilters.js.map +1 -1
  129. package/dist/actions/graphql/gen1/generateTypeQueries.js +2 -1
  130. package/dist/actions/graphql/gen1/generateTypeQueries.js.map +1 -1
  131. package/dist/actions/graphql/gen1/index.js +5 -5
  132. package/dist/actions/graphql/gen1/index.js.map +1 -1
  133. package/dist/actions/graphql/gen2/generateTypeQueries.js +1 -1
  134. package/dist/actions/graphql/gen2/generateTypeQueries.js.map +1 -1
  135. package/dist/actions/graphql/gen2/index.js +6 -6
  136. package/dist/actions/graphql/gen2/index.js.map +1 -1
  137. package/dist/actions/graphql/gen3/generateTypeQueries.js +3 -4
  138. package/dist/actions/graphql/gen3/generateTypeQueries.js.map +1 -1
  139. package/dist/actions/graphql/gen3/index.js +6 -7
  140. package/dist/actions/graphql/gen3/index.js.map +1 -1
  141. package/dist/actions/graphql/getGraphQLAPIs.js +15 -57
  142. package/dist/actions/graphql/getGraphQLAPIs.js.map +1 -1
  143. package/dist/actions/graphql/getGraphQLAPIs.worker.js +75 -106
  144. package/dist/actions/graphql/getGraphQLAPIs.worker.js.map +1 -1
  145. package/dist/actions/graphql/helpers.js +13 -0
  146. package/dist/actions/graphql/helpers.js.map +1 -1
  147. package/dist/actions/graphql/resolveGraphQLApisFromWorkspaces.js +187 -0
  148. package/dist/actions/graphql/resolveGraphQLApisFromWorkspaces.js.map +1 -0
  149. package/dist/actions/graphql/types.js +1 -1
  150. package/dist/actions/graphql/types.js.map +1 -1
  151. package/dist/actions/init/bootstrapLocalTemplate.js +10 -8
  152. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  153. package/dist/actions/init/bootstrapRemoteTemplate.js +6 -5
  154. package/dist/actions/init/bootstrapRemoteTemplate.js.map +1 -1
  155. package/dist/actions/init/bootstrapTemplate.js.map +1 -1
  156. package/dist/actions/init/checkNextJsReactCompatibility.js +1 -1
  157. package/dist/actions/init/checkNextJsReactCompatibility.js.map +1 -1
  158. package/dist/actions/init/createAppCliConfig.js.map +1 -1
  159. package/dist/actions/init/createCliConfig.js.map +1 -1
  160. package/dist/actions/init/createPackageManifest.js +21 -9
  161. package/dist/actions/init/createPackageManifest.js.map +1 -1
  162. package/dist/actions/init/remoteTemplate.js +1 -2
  163. package/dist/actions/init/remoteTemplate.js.map +1 -1
  164. package/dist/actions/init/sdkAppDependencies.js +19 -0
  165. package/dist/actions/init/sdkAppDependencies.js.map +1 -0
  166. package/dist/actions/init/studioDependencies.js.map +1 -0
  167. package/dist/actions/init/templates/appQuickstart.js +1 -22
  168. package/dist/actions/init/templates/appQuickstart.js.map +1 -1
  169. package/dist/actions/init/templates/appSanityUi.js +3 -22
  170. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  171. package/dist/actions/init/types.js.map +1 -1
  172. package/dist/actions/manifest/SchemaIcon.js +6 -4
  173. package/dist/actions/manifest/SchemaIcon.js.map +1 -1
  174. package/dist/actions/manifest/blockTypeTransformer.js +67 -0
  175. package/dist/actions/manifest/blockTypeTransformer.js.map +1 -0
  176. package/dist/actions/manifest/debug.js +4 -0
  177. package/dist/actions/manifest/debug.js.map +1 -0
  178. package/dist/actions/manifest/extractAppManifest.js +39 -22
  179. package/dist/actions/manifest/extractAppManifest.js.map +1 -1
  180. package/dist/actions/manifest/extractManifest.js +27 -78
  181. package/dist/actions/manifest/extractManifest.js.map +1 -1
  182. package/dist/actions/manifest/extractManifest.worker.js +30 -0
  183. package/dist/actions/manifest/extractManifest.worker.js.map +1 -0
  184. package/dist/actions/manifest/extractWorkspaceManifest.js +31 -372
  185. package/dist/actions/manifest/extractWorkspaceManifest.js.map +1 -1
  186. package/dist/actions/manifest/iconResolver.js +30 -0
  187. package/dist/actions/manifest/iconResolver.js.map +1 -0
  188. package/dist/actions/manifest/referenceTransformer.js +51 -0
  189. package/dist/actions/manifest/referenceTransformer.js.map +1 -0
  190. package/dist/actions/manifest/schemaTypeHelpers.js +2 -2
  191. package/dist/actions/manifest/schemaTypeHelpers.js.map +1 -1
  192. package/dist/actions/manifest/schemaTypeTransformer.js +168 -0
  193. package/dist/actions/manifest/schemaTypeTransformer.js.map +1 -0
  194. package/dist/actions/manifest/transformerUtils.js +40 -0
  195. package/dist/actions/manifest/transformerUtils.js.map +1 -0
  196. package/dist/actions/manifest/types.js +5 -0
  197. package/dist/actions/manifest/types.js.map +1 -1
  198. package/dist/actions/manifest/validationTransformer.js +84 -0
  199. package/dist/actions/manifest/validationTransformer.js.map +1 -0
  200. package/dist/actions/manifest/writeManifestFile.js +30 -0
  201. package/dist/actions/manifest/writeManifestFile.js.map +1 -0
  202. package/dist/actions/manifest/writeWorkspaceFiles.js +30 -0
  203. package/dist/actions/manifest/writeWorkspaceFiles.js.map +1 -0
  204. package/dist/actions/mcp/detectAvailableEditors.js +34 -13
  205. package/dist/actions/mcp/detectAvailableEditors.js.map +1 -1
  206. package/dist/actions/mcp/editorConfigs.js +231 -109
  207. package/dist/actions/mcp/editorConfigs.js.map +1 -1
  208. package/dist/actions/mcp/promptForMCPSetup.js +16 -7
  209. package/dist/actions/mcp/promptForMCPSetup.js.map +1 -1
  210. package/dist/actions/mcp/setupMCP.js +62 -23
  211. package/dist/actions/mcp/setupMCP.js.map +1 -1
  212. package/dist/actions/mcp/types.js.map +1 -1
  213. package/dist/actions/mcp/validateEditorTokens.js +56 -0
  214. package/dist/actions/mcp/validateEditorTokens.js.map +1 -0
  215. package/dist/actions/mcp/writeMCPConfig.js +27 -15
  216. package/dist/actions/mcp/writeMCPConfig.js.map +1 -1
  217. package/dist/actions/media/buildNdjsonIndex.js +32 -0
  218. package/dist/actions/media/buildNdjsonIndex.js.map +1 -0
  219. package/dist/actions/media/importAspects.js +2 -11
  220. package/dist/actions/media/importAspects.js.map +1 -1
  221. package/dist/actions/media/importMedia.js +22 -18
  222. package/dist/actions/media/importMedia.js.map +1 -1
  223. package/dist/actions/organizations/findOrganizationByUserName.js +5 -0
  224. package/dist/actions/organizations/findOrganizationByUserName.js.map +1 -0
  225. package/dist/actions/organizations/getOrganization.js +3 -2
  226. package/dist/actions/organizations/getOrganization.js.map +1 -1
  227. package/dist/actions/organizations/getOrganizationChoices.js +27 -19
  228. package/dist/actions/organizations/getOrganizationChoices.js.map +1 -1
  229. package/dist/actions/organizations/types.js +3 -0
  230. package/dist/actions/organizations/types.js.map +1 -0
  231. package/dist/actions/projects/getManageUrl.js +1 -2
  232. package/dist/actions/projects/getManageUrl.js.map +1 -1
  233. package/dist/actions/schema/deleteSchemaAction.js +14 -30
  234. package/dist/actions/schema/deleteSchemaAction.js.map +1 -1
  235. package/dist/actions/schema/deploySchemas.js +22 -91
  236. package/dist/actions/schema/deploySchemas.js.map +1 -1
  237. package/dist/actions/schema/extractSanitySchema.worker.js +0 -5
  238. package/dist/actions/schema/extractSanitySchema.worker.js.map +1 -1
  239. package/dist/actions/schema/extractSanityWorkspace.worker.js +24 -0
  240. package/dist/actions/schema/extractSanityWorkspace.worker.js.map +1 -0
  241. package/dist/actions/schema/extractSchema.js +8 -40
  242. package/dist/actions/schema/extractSchema.js.map +1 -1
  243. package/dist/actions/schema/extractSchemaWatcher.js +128 -0
  244. package/dist/actions/schema/extractSchemaWatcher.js.map +1 -0
  245. package/dist/actions/schema/formatSchemaValidation.js +5 -1
  246. package/dist/actions/schema/formatSchemaValidation.js.map +1 -1
  247. package/dist/actions/schema/getExtractOptions.js +16 -0
  248. package/dist/actions/schema/getExtractOptions.js.map +1 -0
  249. package/dist/actions/schema/listSchemas.js +53 -56
  250. package/dist/actions/schema/listSchemas.js.map +1 -1
  251. package/dist/actions/schema/matchSchemaPattern.js +22 -0
  252. package/dist/actions/schema/matchSchemaPattern.js.map +1 -0
  253. package/dist/actions/schema/runSchemaExtraction.js +39 -0
  254. package/dist/actions/schema/runSchemaExtraction.js.map +1 -0
  255. package/dist/actions/schema/types.js +8 -0
  256. package/dist/actions/schema/types.js.map +1 -1
  257. package/dist/actions/schema/uniqueWorkspaces.worker.js +24 -0
  258. package/dist/actions/schema/uniqueWorkspaces.worker.js.map +1 -0
  259. package/dist/actions/schema/updateWorkspaceSchema.js +63 -0
  260. package/dist/actions/schema/updateWorkspaceSchema.js.map +1 -0
  261. package/dist/actions/schema/uploadSchemaToLexicon.js +87 -0
  262. package/dist/actions/schema/uploadSchemaToLexicon.js.map +1 -0
  263. package/dist/actions/schema/utils/SchemaExtractionError.js +10 -0
  264. package/dist/actions/schema/utils/SchemaExtractionError.js.map +1 -0
  265. package/dist/actions/schema/utils/schemaStoreValidation.js +1 -15
  266. package/dist/actions/schema/utils/schemaStoreValidation.js.map +1 -1
  267. package/dist/actions/schema/utils/uniqByProjectIdDataset.js +1 -1
  268. package/dist/actions/schema/utils/uniqByProjectIdDataset.js.map +1 -1
  269. package/dist/actions/schema/validateSchema.worker.js +1 -8
  270. package/dist/actions/schema/validateSchema.worker.js.map +1 -1
  271. package/dist/actions/schema/watchExtractSchema.js +72 -0
  272. package/dist/actions/schema/watchExtractSchema.js.map +1 -0
  273. package/dist/actions/telemetry/isTrueish.js +10 -0
  274. package/dist/actions/telemetry/isTrueish.js.map +1 -0
  275. package/dist/actions/telemetry/resolveConsent.js +2 -1
  276. package/dist/actions/telemetry/resolveConsent.js.map +1 -1
  277. package/dist/actions/telemetry/setConsent.js +2 -1
  278. package/dist/actions/telemetry/setConsent.js.map +1 -1
  279. package/dist/actions/telemetry/telemetryDebug.js +2 -2
  280. package/dist/actions/telemetry/telemetryDebug.js.map +1 -1
  281. package/dist/actions/users/getMembersForProject.js.map +1 -1
  282. package/dist/actions/users/getPendingInvitations.js +1 -1
  283. package/dist/actions/users/getPendingInvitations.js.map +1 -1
  284. package/dist/actions/users/types.js.map +1 -1
  285. package/dist/actions/versions/filterSanityModules.js.map +1 -1
  286. package/dist/actions/versions/findSanityModulesVersions.js +2 -3
  287. package/dist/actions/versions/findSanityModulesVersions.js.map +1 -1
  288. package/dist/actions/versions/getFormatters.js +1 -1
  289. package/dist/actions/versions/getFormatters.js.map +1 -1
  290. package/dist/actions/versions/tryFindLatestVersion.js +1 -1
  291. package/dist/actions/versions/tryFindLatestVersion.js.map +1 -1
  292. package/dist/commands/backup/disable.js +22 -7
  293. package/dist/commands/backup/disable.js.map +1 -1
  294. package/dist/commands/backup/download.js +19 -10
  295. package/dist/commands/backup/download.js.map +1 -1
  296. package/dist/commands/backup/enable.js +22 -7
  297. package/dist/commands/backup/enable.js.map +1 -1
  298. package/dist/commands/backup/list.js +20 -8
  299. package/dist/commands/backup/list.js.map +1 -1
  300. package/dist/commands/build.js +2 -5
  301. package/dist/commands/build.js.map +1 -1
  302. package/dist/commands/cors/add.js +20 -7
  303. package/dist/commands/cors/add.js.map +1 -1
  304. package/dist/commands/cors/delete.js +22 -7
  305. package/dist/commands/cors/delete.js.map +1 -1
  306. package/dist/commands/cors/list.js +22 -7
  307. package/dist/commands/cors/list.js.map +1 -1
  308. package/dist/commands/dataset/alias/create.js +26 -7
  309. package/dist/commands/dataset/alias/create.js.map +1 -1
  310. package/dist/commands/dataset/alias/delete.js +20 -7
  311. package/dist/commands/dataset/alias/delete.js.map +1 -1
  312. package/dist/commands/dataset/alias/link.js +20 -7
  313. package/dist/commands/dataset/alias/link.js.map +1 -1
  314. package/dist/commands/dataset/alias/unlink.js +20 -7
  315. package/dist/commands/dataset/alias/unlink.js.map +1 -1
  316. package/dist/commands/dataset/copy.js +45 -30
  317. package/dist/commands/dataset/copy.js.map +1 -1
  318. package/dist/commands/dataset/create.js +32 -7
  319. package/dist/commands/dataset/create.js.map +1 -1
  320. package/dist/commands/dataset/delete.js +16 -7
  321. package/dist/commands/dataset/delete.js.map +1 -1
  322. package/dist/commands/dataset/embeddings/disable.js +77 -0
  323. package/dist/commands/dataset/embeddings/disable.js.map +1 -0
  324. package/dist/commands/dataset/embeddings/enable.js +141 -0
  325. package/dist/commands/dataset/embeddings/enable.js.map +1 -0
  326. package/dist/commands/dataset/embeddings/status.js +72 -0
  327. package/dist/commands/dataset/embeddings/status.js.map +1 -0
  328. package/dist/commands/dataset/export.js +25 -16
  329. package/dist/commands/dataset/export.js.map +1 -1
  330. package/dist/commands/dataset/import.js +306 -1
  331. package/dist/commands/dataset/import.js.map +1 -1
  332. package/dist/commands/dataset/list.js +22 -7
  333. package/dist/commands/dataset/list.js.map +1 -1
  334. package/dist/commands/dataset/visibility/get.js +18 -7
  335. package/dist/commands/dataset/visibility/get.js.map +1 -1
  336. package/dist/commands/dataset/visibility/set.js +22 -7
  337. package/dist/commands/dataset/visibility/set.js.map +1 -1
  338. package/dist/commands/debug.js +4 -2
  339. package/dist/commands/debug.js.map +1 -1
  340. package/dist/commands/deploy.js +22 -11
  341. package/dist/commands/deploy.js.map +1 -1
  342. package/dist/commands/dev.js +2 -4
  343. package/dist/commands/dev.js.map +1 -1
  344. package/dist/commands/doctor.js +125 -0
  345. package/dist/commands/doctor.js.map +1 -0
  346. package/dist/commands/documents/create.js +19 -12
  347. package/dist/commands/documents/create.js.map +1 -1
  348. package/dist/commands/documents/delete.js +19 -12
  349. package/dist/commands/documents/delete.js.map +1 -1
  350. package/dist/commands/documents/get.js +17 -12
  351. package/dist/commands/documents/get.js.map +1 -1
  352. package/dist/commands/documents/query.js +26 -18
  353. package/dist/commands/documents/query.js.map +1 -1
  354. package/dist/commands/documents/validate.js +32 -10
  355. package/dist/commands/documents/validate.js.map +1 -1
  356. package/dist/commands/graphql/deploy.js +58 -30
  357. package/dist/commands/graphql/deploy.js.map +1 -1
  358. package/dist/commands/graphql/list.js +15 -7
  359. package/dist/commands/graphql/list.js.map +1 -1
  360. package/dist/commands/graphql/undeploy.js +37 -19
  361. package/dist/commands/graphql/undeploy.js.map +1 -1
  362. package/dist/commands/hook/attempt.js +22 -7
  363. package/dist/commands/hook/attempt.js.map +1 -1
  364. package/dist/commands/hook/create.js +23 -8
  365. package/dist/commands/hook/create.js.map +1 -1
  366. package/dist/commands/hook/delete.js +22 -7
  367. package/dist/commands/hook/delete.js.map +1 -1
  368. package/dist/commands/hook/list.js +22 -7
  369. package/dist/commands/hook/list.js.map +1 -1
  370. package/dist/commands/hook/logs.js +21 -8
  371. package/dist/commands/hook/logs.js.map +1 -1
  372. package/dist/commands/init.js +55 -32
  373. package/dist/commands/init.js.map +1 -1
  374. package/dist/commands/login.js +19 -6
  375. package/dist/commands/login.js.map +1 -1
  376. package/dist/commands/logout.js +8 -6
  377. package/dist/commands/logout.js.map +1 -1
  378. package/dist/commands/manage.js +0 -1
  379. package/dist/commands/manage.js.map +1 -1
  380. package/dist/commands/manifest/extract.js +14 -10
  381. package/dist/commands/manifest/extract.js.map +1 -1
  382. package/dist/commands/mcp/configure.js +4 -2
  383. package/dist/commands/mcp/configure.js.map +1 -1
  384. package/dist/commands/media/create-aspect.js +4 -4
  385. package/dist/commands/media/create-aspect.js.map +1 -1
  386. package/dist/commands/media/delete-aspect.js +9 -7
  387. package/dist/commands/media/delete-aspect.js.map +1 -1
  388. package/dist/commands/media/deploy-aspect.js +22 -9
  389. package/dist/commands/media/deploy-aspect.js.map +1 -1
  390. package/dist/commands/media/export.js +9 -7
  391. package/dist/commands/media/export.js.map +1 -1
  392. package/dist/commands/media/import.js +10 -8
  393. package/dist/commands/media/import.js.map +1 -1
  394. package/dist/commands/preview.js +5 -8
  395. package/dist/commands/preview.js.map +1 -1
  396. package/dist/commands/projects/list.js +2 -1
  397. package/dist/commands/projects/list.js.map +1 -1
  398. package/dist/commands/schema/delete.js +33 -34
  399. package/dist/commands/schema/delete.js.map +1 -1
  400. package/dist/commands/schema/deploy.js +19 -30
  401. package/dist/commands/schema/deploy.js.map +1 -1
  402. package/dist/commands/schema/extract.js +32 -4
  403. package/dist/commands/schema/extract.js.map +1 -1
  404. package/dist/commands/schema/list.js +10 -31
  405. package/dist/commands/schema/list.js.map +1 -1
  406. package/dist/commands/tokens/add.js +24 -7
  407. package/dist/commands/tokens/add.js.map +1 -1
  408. package/dist/commands/tokens/delete.js +20 -7
  409. package/dist/commands/tokens/delete.js.map +1 -1
  410. package/dist/commands/tokens/list.js +20 -7
  411. package/dist/commands/tokens/list.js.map +1 -1
  412. package/dist/commands/users/invite.js +24 -7
  413. package/dist/commands/users/invite.js.map +1 -1
  414. package/dist/commands/users/list.js +76 -33
  415. package/dist/commands/users/list.js.map +1 -1
  416. package/dist/commands/versions.js +1 -1
  417. package/dist/commands/versions.js.map +1 -1
  418. package/dist/config/createCliConfig.js +1 -2
  419. package/dist/config/createCliConfig.js.map +1 -1
  420. package/dist/exports/_internal.d.ts +132 -0
  421. package/dist/exports/_internal.js +4 -0
  422. package/dist/exports/_internal.js.map +1 -0
  423. package/dist/exports/index.d.ts +113 -0
  424. package/dist/exports/index.js +6 -0
  425. package/dist/exports/index.js.map +1 -0
  426. package/dist/hooks/init/checkForUpdates.js +14 -0
  427. package/dist/hooks/init/checkForUpdates.js.map +1 -0
  428. package/dist/hooks/prerun/flushTelemetry.worker.js +1 -1
  429. package/dist/hooks/prerun/flushTelemetry.worker.js.map +1 -1
  430. package/dist/hooks/prerun/injectEnvVariables.js +9 -1
  431. package/dist/hooks/prerun/injectEnvVariables.js.map +1 -1
  432. package/dist/hooks/prerun/setupTelemetry.js +16 -10
  433. package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
  434. package/dist/prompts/promptForProject.js +64 -0
  435. package/dist/prompts/promptForProject.js.map +1 -0
  436. package/dist/{actions/auth/login/promptProviders.js → prompts/promptForProviders.js} +3 -3
  437. package/dist/prompts/promptForProviders.js.map +1 -0
  438. package/dist/prompts/selectMediaLibrary.js +1 -1
  439. package/dist/prompts/selectMediaLibrary.js.map +1 -1
  440. package/dist/server/devServer.js +4 -2
  441. package/dist/server/devServer.js.map +1 -1
  442. package/dist/server/previewServer.js +2 -2
  443. package/dist/server/previewServer.js.map +1 -1
  444. package/dist/server/vite/plugin-schema-extraction.js +201 -0
  445. package/dist/server/vite/plugin-schema-extraction.js.map +1 -0
  446. package/dist/server/vite/plugin-typegen.js +217 -0
  447. package/dist/server/vite/plugin-typegen.js.map +1 -0
  448. package/dist/services/auth.js +42 -3
  449. package/dist/services/auth.js.map +1 -1
  450. package/dist/services/datasets.js +7 -5
  451. package/dist/services/datasets.js.map +1 -1
  452. package/dist/services/docs.js +2 -2
  453. package/dist/services/docs.js.map +1 -1
  454. package/dist/services/embeddings.js +25 -0
  455. package/dist/services/embeddings.js.map +1 -0
  456. package/dist/services/getUrlHeaders.js +7 -18
  457. package/dist/services/getUrlHeaders.js.map +1 -1
  458. package/dist/services/grants.js +13 -0
  459. package/dist/services/grants.js.map +1 -0
  460. package/dist/services/graphql.js +1 -1
  461. package/dist/services/graphql.js.map +1 -1
  462. package/dist/services/mcp.js +55 -1
  463. package/dist/services/mcp.js.map +1 -1
  464. package/dist/services/projects.js +4 -2
  465. package/dist/services/projects.js.map +1 -1
  466. package/dist/services/schemas.js +1 -1
  467. package/dist/services/schemas.js.map +1 -1
  468. package/dist/services/telemetry.js +2 -1
  469. package/dist/services/telemetry.js.map +1 -1
  470. package/dist/services/userApplications.js +21 -6
  471. package/dist/services/userApplications.js.map +1 -1
  472. package/dist/telemetry/extractSchema.telemetry.js +10 -0
  473. package/dist/telemetry/extractSchema.telemetry.js.map +1 -1
  474. package/dist/types/grants.js +3 -0
  475. package/dist/types/grants.js.map +1 -0
  476. package/dist/types.js +3 -0
  477. package/dist/types.js.map +1 -1
  478. package/dist/util/checkProjectPermissions.js +21 -0
  479. package/dist/util/checkProjectPermissions.js.map +1 -0
  480. package/dist/util/cliClient.js +5 -3
  481. package/dist/util/cliClient.js.map +1 -1
  482. package/dist/util/compareDependencyVersions.js +74 -38
  483. package/dist/util/compareDependencyVersions.js.map +1 -1
  484. package/dist/util/createExpiringConfig.js +64 -0
  485. package/dist/util/createExpiringConfig.js.map +1 -0
  486. package/dist/util/detectFramework.js +135 -0
  487. package/dist/util/detectFramework.js.map +1 -0
  488. package/dist/util/errorMessages.js +0 -1
  489. package/dist/util/errorMessages.js.map +1 -1
  490. package/dist/util/extractDocumentsFromNdjsonOrTarball.js +1 -2
  491. package/dist/util/extractDocumentsFromNdjsonOrTarball.js.map +1 -1
  492. package/dist/util/getCliVersion.js +1 -1
  493. package/dist/util/getCliVersion.js.map +1 -1
  494. package/dist/util/getLocalPackageVersion.js +33 -23
  495. package/dist/util/getLocalPackageVersion.js.map +1 -1
  496. package/dist/util/getProjectDefaults.js +22 -28
  497. package/dist/util/getProjectDefaults.js.map +1 -1
  498. package/dist/util/getSharedServerConfig.js +1 -0
  499. package/dist/util/getSharedServerConfig.js.map +1 -1
  500. package/dist/util/getWorkspace.js +1 -1
  501. package/dist/util/getWorkspace.js.map +1 -1
  502. package/dist/util/gitConfig.js +45 -0
  503. package/dist/util/gitConfig.js.map +1 -0
  504. package/dist/util/isSchemaError.js +11 -0
  505. package/dist/util/isSchemaError.js.map +1 -0
  506. package/dist/util/isTar.js +8 -0
  507. package/dist/util/isTar.js.map +1 -0
  508. package/dist/util/packageManager/getPeerDependencies.js +44 -0
  509. package/dist/util/packageManager/getPeerDependencies.js.map +1 -0
  510. package/dist/util/packageManager/installationInfo/analyzeIssues.js +225 -0
  511. package/dist/util/packageManager/installationInfo/analyzeIssues.js.map +1 -0
  512. package/dist/util/packageManager/installationInfo/commands.js +73 -0
  513. package/dist/util/packageManager/installationInfo/commands.js.map +1 -0
  514. package/dist/util/packageManager/installationInfo/detectCliInstallation.js +66 -0
  515. package/dist/util/packageManager/installationInfo/detectCliInstallation.js.map +1 -0
  516. package/dist/util/packageManager/installationInfo/detectGlobals.js +295 -0
  517. package/dist/util/packageManager/installationInfo/detectGlobals.js.map +1 -0
  518. package/dist/util/packageManager/installationInfo/detectPackages.js +190 -0
  519. package/dist/util/packageManager/installationInfo/detectPackages.js.map +1 -0
  520. package/dist/util/packageManager/installationInfo/detectWorkspace.js +192 -0
  521. package/dist/util/packageManager/installationInfo/detectWorkspace.js.map +1 -0
  522. package/dist/util/packageManager/installationInfo/index.js +4 -0
  523. package/dist/util/packageManager/installationInfo/index.js.map +1 -0
  524. package/dist/util/packageManager/installationInfo/readJsonFile.js +14 -0
  525. package/dist/util/packageManager/installationInfo/readJsonFile.js.map +1 -0
  526. package/dist/util/packageManager/installationInfo/resolveVersionRange.js +42 -0
  527. package/dist/util/packageManager/installationInfo/resolveVersionRange.js.map +1 -0
  528. package/dist/util/packageManager/installationInfo/types.js +3 -0
  529. package/dist/util/packageManager/installationInfo/types.js.map +1 -0
  530. package/dist/util/packageManager/packageManagerChoice.js +1 -20
  531. package/dist/util/packageManager/packageManagerChoice.js.map +1 -1
  532. package/dist/util/packageManager/upgradePackages.js +4 -1
  533. package/dist/util/packageManager/upgradePackages.js.map +1 -1
  534. package/dist/util/promiseRaceWithTimeout.js +28 -0
  535. package/dist/util/promiseRaceWithTimeout.js.map +1 -0
  536. package/dist/util/readdirRecursive.js.map +1 -1
  537. package/dist/util/resolveLatestVersions.js +2 -2
  538. package/dist/util/resolveLatestVersions.js.map +1 -1
  539. package/dist/util/sharedFlags.js +54 -0
  540. package/dist/util/sharedFlags.js.map +1 -0
  541. package/dist/util/telemetry/cleanupOldTelemetryFiles.js +30 -0
  542. package/dist/util/telemetry/cleanupOldTelemetryFiles.js.map +1 -0
  543. package/dist/util/telemetry/createTelemetryStore.js +95 -0
  544. package/dist/util/telemetry/createTelemetryStore.js.map +1 -0
  545. package/dist/util/telemetry/createTraceId.js +10 -0
  546. package/dist/util/telemetry/createTraceId.js.map +1 -0
  547. package/dist/util/telemetry/findTelemetryFiles.js +35 -0
  548. package/dist/util/telemetry/findTelemetryFiles.js.map +1 -0
  549. package/dist/util/telemetry/flushTelemetryFiles.js +118 -0
  550. package/dist/util/telemetry/flushTelemetryFiles.js.map +1 -0
  551. package/dist/util/telemetry/generateTelemetryFilePath.js +30 -0
  552. package/dist/util/telemetry/generateTelemetryFilePath.js.map +1 -0
  553. package/dist/util/telemetry/logger.js +59 -0
  554. package/dist/util/telemetry/logger.js.map +1 -0
  555. package/dist/util/telemetry/readNDJSON.js +28 -0
  556. package/dist/util/telemetry/readNDJSON.js.map +1 -0
  557. package/dist/util/telemetry/telemetryStoreDebug.js +7 -0
  558. package/dist/util/telemetry/telemetryStoreDebug.js.map +1 -0
  559. package/dist/util/telemetry/trace.js +150 -0
  560. package/dist/util/telemetry/trace.js.map +1 -0
  561. package/dist/util/toForwardSlashes.js +8 -0
  562. package/dist/util/toForwardSlashes.js.map +1 -0
  563. package/dist/util/update/fetchLatestVersion.js +21 -0
  564. package/dist/util/update/fetchLatestVersion.js.map +1 -0
  565. package/dist/util/update/getUpdateCommand.js +20 -0
  566. package/dist/util/update/getUpdateCommand.js.map +1 -0
  567. package/dist/util/update/isInstalledUsingYarn.js +17 -0
  568. package/dist/util/update/isInstalledUsingYarn.js.map +1 -0
  569. package/dist/util/update/showNotificationUpdate.js +31 -0
  570. package/dist/util/update/showNotificationUpdate.js.map +1 -0
  571. package/dist/util/update/updateChecker.js +60 -0
  572. package/dist/util/update/updateChecker.js.map +1 -0
  573. package/dist/util/update/updateCheckerDebug.js +4 -0
  574. package/dist/util/update/updateCheckerDebug.js.map +1 -0
  575. package/oclif.config.js +1 -0
  576. package/oclif.manifest.json +1285 -492
  577. package/package.json +72 -73
  578. package/static/favicons/apple-touch-icon.png +0 -0
  579. package/static/favicons/favicon-192.png +0 -0
  580. package/static/favicons/favicon-512.png +0 -0
  581. package/static/favicons/favicon-96.png +0 -0
  582. package/static/favicons/favicon.ico +0 -0
  583. package/static/favicons/favicon.svg +12 -0
  584. package/dist/actions/auth/login/promptProviders.js.map +0 -1
  585. package/dist/actions/dev/getCoreAppUrl.js +0 -10
  586. package/dist/actions/dev/getCoreAppUrl.js.map +0 -1
  587. package/dist/actions/schema/schemaStoreTypes.js +0 -19
  588. package/dist/actions/schema/schemaStoreTypes.js.map +0 -1
  589. package/dist/actions/schema/utils/manifestExtractor.js +0 -33
  590. package/dist/actions/schema/utils/manifestExtractor.js.map +0 -1
  591. package/dist/actions/schema/utils/manifestReader.js +0 -71
  592. package/dist/actions/schema/utils/manifestReader.js.map +0 -1
  593. package/dist/index.d.ts +0 -2326
  594. package/dist/index.js +0 -6
  595. package/dist/index.js.map +0 -1
  596. package/dist/studioDependencies.js.map +0 -1
  597. package/dist/typings/deepSortObject.d.js +0 -2
  598. package/dist/typings/deepSortObject.d.js.map +0 -1
  599. package/dist/util/findNdjsonEntry.js +0 -21
  600. package/dist/util/findNdjsonEntry.js.map +0 -1
  601. package/dist/util/importStudioConfig.js +0 -40
  602. package/dist/util/importStudioConfig.js.map +0 -1
  603. package/dist/util/readModuleVersion.js +0 -15
  604. package/dist/util/readModuleVersion.js.map +0 -1
  605. package/dist/util/readPackageJson.js +0 -44
  606. package/dist/util/readPackageJson.js.map +0 -1
  607. package/dist/util/readPackageManifest.js +0 -46
  608. package/dist/util/readPackageManifest.js.map +0 -1
  609. package/dist/util/uniqBy.js +0 -14
  610. package/dist/util/uniqBy.js.map +0 -1
  611. package/dist/util/workerChannels.js +0 -172
  612. package/dist/util/workerChannels.js.map +0 -1
  613. /package/dist/{studioDependencies.js → actions/init/studioDependencies.js} +0 -0
@@ -1,19 +1,28 @@
1
1
  import { checkbox } from '@sanity/cli-core/ux';
2
+ function getEditorLabel(editor) {
3
+ if (editor.configured && editor.authStatus === 'unauthorized') {
4
+ return `${editor.name} (auth expired)`;
5
+ }
6
+ if (editor.configured && !editor.existingToken) {
7
+ return `${editor.name} (missing credentials)`;
8
+ }
9
+ return editor.name;
10
+ }
2
11
  /**
3
- * Prompt user to select which editors to configure
4
- * Shows existing config status - unconfigured editors are pre-selected,
5
- * configured editors show "(already installed)" and are not pre-selected
12
+ * Prompt user to select which editors to configure.
13
+ *
14
+ * Expects only actionable editors (unconfigured, or configured with
15
+ * invalid/missing credentials). Annotates entries with auth status.
6
16
  */ export async function promptForMCPSetup(editors) {
7
17
  const editorChoices = editors.map((e)=>({
8
- checked: !e.configured,
9
- name: e.configured ? `${e.name} (already installed)` : e.name,
18
+ checked: true,
19
+ name: getEditorLabel(e),
10
20
  value: e.name
11
21
  }));
12
- const result = await checkbox({
22
+ const selectedNames = await checkbox({
13
23
  choices: editorChoices,
14
24
  message: 'Configure Sanity MCP server?'
15
25
  });
16
- const selectedNames = result;
17
26
  // User can deselect all to skip
18
27
  if (!selectedNames || selectedNames.length === 0) {
19
28
  return null;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\n/**\n * Prompt user to select which editors to configure\n * Shows existing config status - unconfigured editors are pre-selected,\n * configured editors show \"(already installed)\" and are not pre-selected\n */\nexport async function promptForMCPSetup(editors: Editor[]): Promise<Editor[] | null> {\n const editorChoices = editors.map((e) => ({\n checked: !e.configured, // Only pre-select if NOT already configured\n name: e.configured ? `${e.name} (already installed)` : e.name,\n value: e.name,\n }))\n\n const result = await checkbox({\n choices: editorChoices,\n message: 'Configure Sanity MCP server?',\n })\n\n const selectedNames = result\n\n // User can deselect all to skip\n if (!selectedNames || selectedNames.length === 0) {\n return null\n }\n\n return editors.filter((e) => selectedNames.includes(e.name))\n}\n"],"names":["checkbox","promptForMCPSetup","editors","editorChoices","map","e","checked","configured","name","value","result","choices","message","selectedNames","length","filter","includes"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAqB;AAI5C;;;;CAIC,GACD,OAAO,eAAeC,kBAAkBC,OAAiB;IACvD,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC,CAACC,IAAO,CAAA;YACxCC,SAAS,CAACD,EAAEE,UAAU;YACtBC,MAAMH,EAAEE,UAAU,GAAG,GAAGF,EAAEG,IAAI,CAAC,oBAAoB,CAAC,GAAGH,EAAEG,IAAI;YAC7DC,OAAOJ,EAAEG,IAAI;QACf,CAAA;IAEA,MAAME,SAAS,MAAMV,SAAS;QAC5BW,SAASR;QACTS,SAAS;IACX;IAEA,MAAMC,gBAAgBH;IAEtB,gCAAgC;IAChC,IAAI,CAACG,iBAAiBA,cAAcC,MAAM,KAAK,GAAG;QAChD,OAAO;IACT;IAEA,OAAOZ,QAAQa,MAAM,CAAC,CAACV,IAAMQ,cAAcG,QAAQ,CAACX,EAAEG,IAAI;AAC5D"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/promptForMCPSetup.ts"],"sourcesContent":["import {checkbox} from '@sanity/cli-core/ux'\n\nimport {type Editor} from './types.js'\n\nfunction getEditorLabel(editor: Editor): string {\n if (editor.configured && editor.authStatus === 'unauthorized') {\n return `${editor.name} (auth expired)`\n }\n if (editor.configured && !editor.existingToken) {\n return `${editor.name} (missing credentials)`\n }\n return editor.name\n}\n\n/**\n * Prompt user to select which editors to configure.\n *\n * Expects only actionable editors (unconfigured, or configured with\n * invalid/missing credentials). Annotates entries with auth status.\n */\nexport async function promptForMCPSetup(editors: Editor[]): Promise<Editor[] | null> {\n const editorChoices = editors.map((e) => ({\n checked: true, // Pre-select all actionable editors\n name: getEditorLabel(e),\n value: e.name,\n }))\n\n const selectedNames = await checkbox({\n choices: editorChoices,\n message: 'Configure Sanity MCP server?',\n })\n\n // User can deselect all to skip\n if (!selectedNames || selectedNames.length === 0) {\n return null\n }\n\n return editors.filter((e) => selectedNames.includes(e.name))\n}\n"],"names":["checkbox","getEditorLabel","editor","configured","authStatus","name","existingToken","promptForMCPSetup","editors","editorChoices","map","e","checked","value","selectedNames","choices","message","length","filter","includes"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAqB;AAI5C,SAASC,eAAeC,MAAc;IACpC,IAAIA,OAAOC,UAAU,IAAID,OAAOE,UAAU,KAAK,gBAAgB;QAC7D,OAAO,GAAGF,OAAOG,IAAI,CAAC,eAAe,CAAC;IACxC;IACA,IAAIH,OAAOC,UAAU,IAAI,CAACD,OAAOI,aAAa,EAAE;QAC9C,OAAO,GAAGJ,OAAOG,IAAI,CAAC,sBAAsB,CAAC;IAC/C;IACA,OAAOH,OAAOG,IAAI;AACpB;AAEA;;;;;CAKC,GACD,OAAO,eAAeE,kBAAkBC,OAAiB;IACvD,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC,CAACC,IAAO,CAAA;YACxCC,SAAS;YACTP,MAAMJ,eAAeU;YACrBE,OAAOF,EAAEN,IAAI;QACf,CAAA;IAEA,MAAMS,gBAAgB,MAAMd,SAAS;QACnCe,SAASN;QACTO,SAAS;IACX;IAEA,gCAAgC;IAChC,IAAI,CAACF,iBAAiBA,cAAcG,MAAM,KAAK,GAAG;QAChD,OAAO;IACT;IAEA,OAAOT,QAAQU,MAAM,CAAC,CAACP,IAAMG,cAAcK,QAAQ,CAACR,EAAEN,IAAI;AAC5D"}
@@ -4,17 +4,20 @@ import { logSymbols } from '@sanity/cli-core/ux';
4
4
  import { createMCPToken, MCP_SERVER_URL } from '../../services/mcp.js';
5
5
  import { detectAvailableEditors } from './detectAvailableEditors.js';
6
6
  import { promptForMCPSetup } from './promptForMCPSetup.js';
7
+ import { validateEditorTokens } from './validateEditorTokens.js';
7
8
  import { writeMCPConfig } from './writeMCPConfig.js';
8
9
  const mcpDebug = subdebug('mcp:setup');
9
10
  const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`;
10
11
  /**
11
12
  * Main MCP setup orchestration
12
- * Opt-out by default: runs automatically unless skipMcp flag is set
13
- */ export async function setupMCP(mcp) {
13
+ * Opt-out by default: runs automatically unless skip option is set
14
+ */ export async function setupMCP(options) {
15
+ const { explicit = false, skip = false } = options ?? {};
14
16
  // 1. Check for explicit opt-out
15
- if (mcp === false) {
17
+ if (skip) {
16
18
  ux.warn('Skipping MCP configuration due to --no-mcp flag');
17
19
  return {
20
+ alreadyConfiguredEditors: [],
18
21
  configuredEditors: [],
19
22
  detectedEditors: [],
20
23
  skipped: true
@@ -25,44 +28,79 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
25
28
  const detectedEditors = editors.map((e)=>e.name);
26
29
  mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors);
27
30
  if (editors.length === 0) {
28
- ux.warn(NO_EDITORS_DETECTED_MESSAGE);
31
+ if (explicit) {
32
+ ux.warn(NO_EDITORS_DETECTED_MESSAGE);
33
+ }
29
34
  return {
35
+ alreadyConfiguredEditors: [],
30
36
  configuredEditors: [],
31
37
  detectedEditors,
32
38
  skipped: true
33
39
  };
34
40
  }
35
- // 3. Prompt user (shows existing config status, only pre-selects unconfigured editors)
36
- const selected = await promptForMCPSetup(editors);
37
- if (!selected || selected.length === 0) {
38
- // User deselected all editors
39
- ux.stdout('MCP configuration skipped');
41
+ // 3. Validate existing tokens against the Sanity API
42
+ await validateEditorTokens(editors);
43
+ // 4. Check if there's anything actionable
44
+ const actionable = editors.filter((e)=>!e.configured || e.authStatus !== 'valid');
45
+ if (actionable.length === 0) {
46
+ mcpDebug('All editors configured with valid credentials');
47
+ const alreadyConfiguredEditors = editors.filter((e)=>e.configured && e.authStatus === 'valid').map((e)=>e.name);
48
+ if (explicit) {
49
+ ux.stdout(`${logSymbols.success} All detected editors are already configured`);
50
+ }
40
51
  return {
52
+ alreadyConfiguredEditors,
41
53
  configuredEditors: [],
42
54
  detectedEditors,
43
55
  skipped: true
44
56
  };
45
57
  }
46
- // 4. Create child token for MCP
47
- let token;
48
- try {
49
- token = await createMCPToken();
50
- } catch (error) {
51
- const err = error instanceof Error ? error : new Error(String(error));
52
- mcpDebug('Error creating MCP token', error);
53
- ux.warn(`Could not configure MCP: ${err.message}`);
54
- ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
58
+ // Non-actionable editors are already configured with valid credentials
59
+ const alreadyConfiguredEditors = editors.filter((e)=>!actionable.includes(e)).map((e)=>e.name);
60
+ // 5. Prompt user (shows only actionable editors, annotates auth issues)
61
+ const selected = await promptForMCPSetup(actionable);
62
+ if (!selected || selected.length === 0) {
63
+ // User deselected all editors
64
+ ux.stdout('MCP configuration skipped');
55
65
  return {
66
+ alreadyConfiguredEditors,
56
67
  configuredEditors: [],
57
68
  detectedEditors,
58
- error: err,
59
- skipped: false
69
+ skipped: true
60
70
  };
61
71
  }
62
- // 5. Write configs for each selected editor
72
+ // 6. Get a token reuse a valid existing one or create a new one
73
+ let token;
74
+ // Look for an existing valid token we can reuse
75
+ const validEditor = editors.find((e)=>e.authStatus === 'valid' && e.existingToken);
76
+ if (validEditor?.existingToken) {
77
+ mcpDebug('Reusing valid token from %s', validEditor.name);
78
+ token = validEditor.existingToken;
79
+ }
80
+ // Fall back to creating a new token
81
+ if (!token) {
82
+ try {
83
+ token = await createMCPToken();
84
+ } catch (error) {
85
+ const err = error instanceof Error ? error : new Error(String(error));
86
+ mcpDebug('Error creating MCP token', error);
87
+ ux.warn(`Could not configure MCP: ${err.message}`);
88
+ ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
89
+ return {
90
+ alreadyConfiguredEditors,
91
+ configuredEditors: [],
92
+ detectedEditors,
93
+ error: err,
94
+ skipped: false
95
+ };
96
+ }
97
+ }
98
+ // 7. Write configs for each selected editor
99
+ const configuredEditors = [];
63
100
  try {
64
101
  for (const editor of selected){
65
102
  await writeMCPConfig(editor, token);
103
+ configuredEditors.push(editor.name);
66
104
  }
67
105
  } catch (error) {
68
106
  const err = error instanceof Error ? error : new Error(String(error));
@@ -70,15 +108,16 @@ const NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server f
70
108
  ux.warn(`Could not configure MCP: ${err.message}`);
71
109
  ux.warn('You can set up MCP manually later using https://mcp.sanity.io');
72
110
  return {
73
- configuredEditors: [],
111
+ alreadyConfiguredEditors,
112
+ configuredEditors,
74
113
  detectedEditors,
75
114
  error: err,
76
115
  skipped: false
77
116
  };
78
117
  }
79
- const configuredEditors = selected.map((e)=>e.name);
80
118
  ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`);
81
119
  return {
120
+ alreadyConfiguredEditors,
82
121
  configuredEditors,
83
122
  detectedEditors,
84
123
  skipped: false
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {type EditorName} from './editorConfigs.js'\nimport {promptForMCPSetup} from './promptForMCPSetup.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\nexport interface MCPSetupResult {\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n skipped: boolean\n\n error?: Error\n}\n\n/**\n * Main MCP setup orchestration\n * Opt-out by default: runs automatically unless skipMcp flag is set\n */\nexport async function setupMCP(mcp?: boolean): Promise<MCPSetupResult> {\n // 1. Check for explicit opt-out\n if (mcp === false) {\n ux.warn('Skipping MCP configuration due to --no-mcp flag')\n return {\n configuredEditors: [],\n detectedEditors: [],\n skipped: true,\n }\n }\n\n // 2. Detect available editors (filters out unparseable configs)\n const editors = await detectAvailableEditors()\n const detectedEditors = editors.map((e) => e.name)\n\n mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors)\n\n if (editors.length === 0) {\n ux.warn(NO_EDITORS_DETECTED_MESSAGE)\n return {\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 3. Prompt user (shows existing config status, only pre-selects unconfigured editors)\n const selected = await promptForMCPSetup(editors)\n\n if (!selected || selected.length === 0) {\n // User deselected all editors\n ux.stdout('MCP configuration skipped')\n return {\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 4. Create child token for MCP\n let token: string\n try {\n token = await createMCPToken()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error creating MCP token', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n configuredEditors: [],\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n\n // 5. Write configs for each selected editor\n try {\n for (const editor of selected) {\n await writeMCPConfig(editor, token)\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error writing MCP config', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n configuredEditors: [],\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n\n const configuredEditors = selected.map((e) => e.name)\n ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`)\n\n return {\n configuredEditors,\n detectedEditors,\n skipped: false,\n }\n}\n"],"names":["ux","subdebug","logSymbols","createMCPToken","MCP_SERVER_URL","detectAvailableEditors","promptForMCPSetup","writeMCPConfig","mcpDebug","NO_EDITORS_DETECTED_MESSAGE","setupMCP","mcp","warn","configuredEditors","detectedEditors","skipped","editors","map","e","name","length","selected","stdout","token","error","err","Error","String","message","editor","success","join"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,UAAU,QAAO,sBAAqB;AAE9C,SAAQC,cAAc,EAAEC,cAAc,QAAO,wBAAuB;AACpE,SAAQC,sBAAsB,QAAO,8BAA6B;AAElE,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,cAAc,QAAO,sBAAqB;AAElD,MAAMC,WAAWP,SAAS;AAE1B,MAAMQ,8BAA8B,CAAC,iEAAiE,EAAEL,eAAe,wBAAwB,CAAC;AAUhJ;;;CAGC,GACD,OAAO,eAAeM,SAASC,GAAa;IAC1C,gCAAgC;IAChC,IAAIA,QAAQ,OAAO;QACjBX,GAAGY,IAAI,CAAC;QACR,OAAO;YACLC,mBAAmB,EAAE;YACrBC,iBAAiB,EAAE;YACnBC,SAAS;QACX;IACF;IAEA,gEAAgE;IAChE,MAAMC,UAAU,MAAMX;IACtB,MAAMS,kBAAkBE,QAAQC,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;IAEjDX,SAAS,2BAA2BM,gBAAgBM,MAAM,EAAEN;IAE5D,IAAIE,QAAQI,MAAM,KAAK,GAAG;QACxBpB,GAAGY,IAAI,CAACH;QACR,OAAO;YACLI,mBAAmB,EAAE;YACrBC;YACAC,SAAS;QACX;IACF;IAEA,uFAAuF;IACvF,MAAMM,WAAW,MAAMf,kBAAkBU;IAEzC,IAAI,CAACK,YAAYA,SAASD,MAAM,KAAK,GAAG;QACtC,8BAA8B;QAC9BpB,GAAGsB,MAAM,CAAC;QACV,OAAO;YACLT,mBAAmB,EAAE;YACrBC;YACAC,SAAS;QACX;IACF;IAEA,gCAAgC;IAChC,IAAIQ;IACJ,IAAI;QACFA,QAAQ,MAAMpB;IAChB,EAAE,OAAOqB,OAAO;QACd,MAAMC,MAAMD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMC,OAAOH;QAC9DhB,SAAS,4BAA4BgB;QACrCxB,GAAGY,IAAI,CAAC,CAAC,yBAAyB,EAAEa,IAAIG,OAAO,EAAE;QACjD5B,GAAGY,IAAI,CAAC;QACR,OAAO;YACLC,mBAAmB,EAAE;YACrBC;YACAU,OAAOC;YACPV,SAAS;QACX;IACF;IAEA,4CAA4C;IAC5C,IAAI;QACF,KAAK,MAAMc,UAAUR,SAAU;YAC7B,MAAMd,eAAesB,QAAQN;QAC/B;IACF,EAAE,OAAOC,OAAO;QACd,MAAMC,MAAMD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMC,OAAOH;QAC9DhB,SAAS,4BAA4BgB;QACrCxB,GAAGY,IAAI,CAAC,CAAC,yBAAyB,EAAEa,IAAIG,OAAO,EAAE;QACjD5B,GAAGY,IAAI,CAAC;QACR,OAAO;YACLC,mBAAmB,EAAE;YACrBC;YACAU,OAAOC;YACPV,SAAS;QACX;IACF;IAEA,MAAMF,oBAAoBQ,SAASJ,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;IACpDnB,GAAGsB,MAAM,CAAC,GAAGpB,WAAW4B,OAAO,CAAC,oBAAoB,EAAEjB,kBAAkBkB,IAAI,CAAC,OAAO;IAEpF,OAAO;QACLlB;QACAC;QACAC,SAAS;IACX;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/setupMCP.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {createMCPToken, MCP_SERVER_URL} from '../../services/mcp.js'\nimport {detectAvailableEditors} from './detectAvailableEditors.js'\nimport {type EditorName} from './editorConfigs.js'\nimport {promptForMCPSetup} from './promptForMCPSetup.js'\nimport {validateEditorTokens} from './validateEditorTokens.js'\nimport {writeMCPConfig} from './writeMCPConfig.js'\n\nconst mcpDebug = subdebug('mcp:setup')\n\nconst NO_EDITORS_DETECTED_MESSAGE = `Couldn't auto-configure Sanity MCP server for your editor. Visit ${MCP_SERVER_URL} for setup instructions.`\n\ninterface MCPSetupOptions {\n /**\n * Whether the user explicitly requested MCP configuration (e.g. `sanity mcp configure`).\n * When true, shows status messages even when there's nothing to do.\n * When false/undefined (e.g. called from `sanity init`), stays quiet.\n */\n explicit?: boolean\n\n /**\n * If true, skip MCP configuration entirely (e.g. --no-mcp flag).\n */\n skip?: boolean\n}\n\ninterface MCPSetupResult {\n /** Editors that were already configured with valid credentials (nothing to do) */\n alreadyConfiguredEditors: EditorName[]\n configuredEditors: EditorName[]\n detectedEditors: EditorName[]\n skipped: boolean\n\n error?: Error\n}\n\n/**\n * Main MCP setup orchestration\n * Opt-out by default: runs automatically unless skip option is set\n */\nexport async function setupMCP(options?: MCPSetupOptions): Promise<MCPSetupResult> {\n const {explicit = false, skip = false} = options ?? {}\n\n // 1. Check for explicit opt-out\n if (skip) {\n ux.warn('Skipping MCP configuration due to --no-mcp flag')\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors: [],\n skipped: true,\n }\n }\n\n // 2. Detect available editors (filters out unparseable configs)\n const editors = await detectAvailableEditors()\n const detectedEditors = editors.map((e) => e.name)\n\n mcpDebug('Detected %d editors: %s', detectedEditors.length, detectedEditors)\n\n if (editors.length === 0) {\n if (explicit) {\n ux.warn(NO_EDITORS_DETECTED_MESSAGE)\n }\n return {\n alreadyConfiguredEditors: [],\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 3. Validate existing tokens against the Sanity API\n await validateEditorTokens(editors)\n\n // 4. Check if there's anything actionable\n const actionable = editors.filter((e) => !e.configured || e.authStatus !== 'valid')\n\n if (actionable.length === 0) {\n mcpDebug('All editors configured with valid credentials')\n const alreadyConfiguredEditors = editors\n .filter((e) => e.configured && e.authStatus === 'valid')\n .map((e) => e.name)\n if (explicit) {\n ux.stdout(`${logSymbols.success} All detected editors are already configured`)\n }\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // Non-actionable editors are already configured with valid credentials\n const alreadyConfiguredEditors = editors.filter((e) => !actionable.includes(e)).map((e) => e.name)\n\n // 5. Prompt user (shows only actionable editors, annotates auth issues)\n const selected = await promptForMCPSetup(actionable)\n\n if (!selected || selected.length === 0) {\n // User deselected all editors\n ux.stdout('MCP configuration skipped')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n skipped: true,\n }\n }\n\n // 6. Get a token reuse a valid existing one or create a new one\n let token: string | undefined\n\n // Look for an existing valid token we can reuse\n const validEditor = editors.find((e) => e.authStatus === 'valid' && e.existingToken)\n if (validEditor?.existingToken) {\n mcpDebug('Reusing valid token from %s', validEditor.name)\n token = validEditor.existingToken\n }\n\n // Fall back to creating a new token\n if (!token) {\n try {\n token = await createMCPToken()\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error creating MCP token', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors: [],\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n }\n\n // 7. Write configs for each selected editor\n const configuredEditors: EditorName[] = []\n try {\n for (const editor of selected) {\n await writeMCPConfig(editor, token)\n configuredEditors.push(editor.name)\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n mcpDebug('Error writing MCP config', error)\n ux.warn(`Could not configure MCP: ${err.message}`)\n ux.warn('You can set up MCP manually later using https://mcp.sanity.io')\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n error: err,\n skipped: false,\n }\n }\n\n ux.stdout(`${logSymbols.success} MCP configured for ${configuredEditors.join(', ')}`)\n\n return {\n alreadyConfiguredEditors,\n configuredEditors,\n detectedEditors,\n skipped: false,\n }\n}\n"],"names":["ux","subdebug","logSymbols","createMCPToken","MCP_SERVER_URL","detectAvailableEditors","promptForMCPSetup","validateEditorTokens","writeMCPConfig","mcpDebug","NO_EDITORS_DETECTED_MESSAGE","setupMCP","options","explicit","skip","warn","alreadyConfiguredEditors","configuredEditors","detectedEditors","skipped","editors","map","e","name","length","actionable","filter","configured","authStatus","stdout","success","includes","selected","token","validEditor","find","existingToken","error","err","Error","String","message","editor","push","join"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,UAAU,QAAO,sBAAqB;AAE9C,SAAQC,cAAc,EAAEC,cAAc,QAAO,wBAAuB;AACpE,SAAQC,sBAAsB,QAAO,8BAA6B;AAElE,SAAQC,iBAAiB,QAAO,yBAAwB;AACxD,SAAQC,oBAAoB,QAAO,4BAA2B;AAC9D,SAAQC,cAAc,QAAO,sBAAqB;AAElD,MAAMC,WAAWR,SAAS;AAE1B,MAAMS,8BAA8B,CAAC,iEAAiE,EAAEN,eAAe,wBAAwB,CAAC;AA0BhJ;;;CAGC,GACD,OAAO,eAAeO,SAASC,OAAyB;IACtD,MAAM,EAACC,WAAW,KAAK,EAAEC,OAAO,KAAK,EAAC,GAAGF,WAAW,CAAC;IAErD,gCAAgC;IAChC,IAAIE,MAAM;QACRd,GAAGe,IAAI,CAAC;QACR,OAAO;YACLC,0BAA0B,EAAE;YAC5BC,mBAAmB,EAAE;YACrBC,iBAAiB,EAAE;YACnBC,SAAS;QACX;IACF;IAEA,gEAAgE;IAChE,MAAMC,UAAU,MAAMf;IACtB,MAAMa,kBAAkBE,QAAQC,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;IAEjDd,SAAS,2BAA2BS,gBAAgBM,MAAM,EAAEN;IAE5D,IAAIE,QAAQI,MAAM,KAAK,GAAG;QACxB,IAAIX,UAAU;YACZb,GAAGe,IAAI,CAACL;QACV;QACA,OAAO;YACLM,0BAA0B,EAAE;YAC5BC,mBAAmB,EAAE;YACrBC;YACAC,SAAS;QACX;IACF;IAEA,qDAAqD;IACrD,MAAMZ,qBAAqBa;IAE3B,0CAA0C;IAC1C,MAAMK,aAAaL,QAAQM,MAAM,CAAC,CAACJ,IAAM,CAACA,EAAEK,UAAU,IAAIL,EAAEM,UAAU,KAAK;IAE3E,IAAIH,WAAWD,MAAM,KAAK,GAAG;QAC3Bf,SAAS;QACT,MAAMO,2BAA2BI,QAC9BM,MAAM,CAAC,CAACJ,IAAMA,EAAEK,UAAU,IAAIL,EAAEM,UAAU,KAAK,SAC/CP,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;QACpB,IAAIV,UAAU;YACZb,GAAG6B,MAAM,CAAC,GAAG3B,WAAW4B,OAAO,CAAC,4CAA4C,CAAC;QAC/E;QACA,OAAO;YACLd;YACAC,mBAAmB,EAAE;YACrBC;YACAC,SAAS;QACX;IACF;IAEA,uEAAuE;IACvE,MAAMH,2BAA2BI,QAAQM,MAAM,CAAC,CAACJ,IAAM,CAACG,WAAWM,QAAQ,CAACT,IAAID,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;IAEjG,wEAAwE;IACxE,MAAMS,WAAW,MAAM1B,kBAAkBmB;IAEzC,IAAI,CAACO,YAAYA,SAASR,MAAM,KAAK,GAAG;QACtC,8BAA8B;QAC9BxB,GAAG6B,MAAM,CAAC;QACV,OAAO;YACLb;YACAC,mBAAmB,EAAE;YACrBC;YACAC,SAAS;QACX;IACF;IAEA,kEAAkE;IAClE,IAAIc;IAEJ,gDAAgD;IAChD,MAAMC,cAAcd,QAAQe,IAAI,CAAC,CAACb,IAAMA,EAAEM,UAAU,KAAK,WAAWN,EAAEc,aAAa;IACnF,IAAIF,aAAaE,eAAe;QAC9B3B,SAAS,+BAA+ByB,YAAYX,IAAI;QACxDU,QAAQC,YAAYE,aAAa;IACnC;IAEA,oCAAoC;IACpC,IAAI,CAACH,OAAO;QACV,IAAI;YACFA,QAAQ,MAAM9B;QAChB,EAAE,OAAOkC,OAAO;YACd,MAAMC,MAAMD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMC,OAAOH;YAC9D5B,SAAS,4BAA4B4B;YACrCrC,GAAGe,IAAI,CAAC,CAAC,yBAAyB,EAAEuB,IAAIG,OAAO,EAAE;YACjDzC,GAAGe,IAAI,CAAC;YACR,OAAO;gBACLC;gBACAC,mBAAmB,EAAE;gBACrBC;gBACAmB,OAAOC;gBACPnB,SAAS;YACX;QACF;IACF;IAEA,4CAA4C;IAC5C,MAAMF,oBAAkC,EAAE;IAC1C,IAAI;QACF,KAAK,MAAMyB,UAAUV,SAAU;YAC7B,MAAMxB,eAAekC,QAAQT;YAC7BhB,kBAAkB0B,IAAI,CAACD,OAAOnB,IAAI;QACpC;IACF,EAAE,OAAOc,OAAO;QACd,MAAMC,MAAMD,iBAAiBE,QAAQF,QAAQ,IAAIE,MAAMC,OAAOH;QAC9D5B,SAAS,4BAA4B4B;QACrCrC,GAAGe,IAAI,CAAC,CAAC,yBAAyB,EAAEuB,IAAIG,OAAO,EAAE;QACjDzC,GAAGe,IAAI,CAAC;QACR,OAAO;YACLC;YACAC;YACAC;YACAmB,OAAOC;YACPnB,SAAS;QACX;IACF;IAEAnB,GAAG6B,MAAM,CAAC,GAAG3B,WAAW4B,OAAO,CAAC,oBAAoB,EAAEb,kBAAkB2B,IAAI,CAAC,OAAO;IAEpF,OAAO;QACL5B;QACAC;QACAC;QACAC,SAAS;IACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n}\n"],"names":[],"mappings":"AAEA,WAKC"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/types.ts"],"sourcesContent":["import {type EditorName} from './editorConfigs.js'\n\n/** Auth credential status for a configured editor */\nexport type AuthStatus = 'unauthorized' | 'valid'\n\nexport interface Editor {\n configPath: string\n /** Whether Sanity MCP is already configured for this editor */\n configured: boolean\n name: EditorName\n\n /**\n * Auth status of the existing token. Only set for editors that have\n * a Sanity MCP config with a token that has been validated against the API.\n */\n authStatus?: AuthStatus\n /** The existing auth token found in the editor config, if any */\n existingToken?: string\n}\n"],"names":[],"mappings":"AAKA,WAaC"}
@@ -0,0 +1,56 @@
1
+ import { subdebug } from '@sanity/cli-core';
2
+ import { validateMCPToken } from '../../services/mcp.js';
3
+ const debug = subdebug('mcp:validateEditorTokens');
4
+ /**
5
+ * Validate existing MCP tokens for all configured editors.
6
+ *
7
+ * Collects unique tokens, validates each once against the Sanity API,
8
+ * and sets `authStatus` on each editor that has a token.
9
+ * Editors without a config or token are left unchanged.
10
+ */ export async function validateEditorTokens(editors) {
11
+ // Collect unique tokens and map them to their editors
12
+ const tokenToEditors = new Map();
13
+ for (const editor of editors){
14
+ if (editor.existingToken) {
15
+ const existing = tokenToEditors.get(editor.existingToken);
16
+ if (existing) {
17
+ existing.push(editor);
18
+ } else {
19
+ tokenToEditors.set(editor.existingToken, [
20
+ editor
21
+ ]);
22
+ }
23
+ }
24
+ }
25
+ if (tokenToEditors.size === 0) {
26
+ debug('No existing tokens to validate');
27
+ return;
28
+ }
29
+ const editorCount = [
30
+ ...tokenToEditors.values()
31
+ ].reduce((sum, eds)=>sum + eds.length, 0);
32
+ debug('Validating %d unique token(s) across %d editor(s)', tokenToEditors.size, editorCount);
33
+ // Validate all unique tokens in parallel to avoid stacking timeouts
34
+ await Promise.all([
35
+ ...tokenToEditors.entries()
36
+ ].map(async ([token, tokenEditors])=>{
37
+ let status;
38
+ try {
39
+ const valid = await validateMCPToken(token);
40
+ status = valid ? 'valid' : 'unauthorized';
41
+ } catch (err) {
42
+ // Network errors, timeouts, or unexpected failures — assume the token
43
+ // is valid rather than falsely marking it as expired. We only mark
44
+ // tokens as unauthorized when the server explicitly says so (401/403).
45
+ debug('Token validation error (assuming valid): %s', err);
46
+ status = 'valid';
47
+ }
48
+ debug('Token ending ...%s is %s (used by %s)', token.slice(-4), status, tokenEditors.map((e)=>e.name).join(', '));
49
+ // Apply status to all editors sharing this token
50
+ for (const editor of tokenEditors){
51
+ editor.authStatus = status;
52
+ }
53
+ }));
54
+ }
55
+
56
+ //# sourceMappingURL=validateEditorTokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/mcp/validateEditorTokens.ts"],"sourcesContent":["import {subdebug} from '@sanity/cli-core'\n\nimport {validateMCPToken} from '../../services/mcp.js'\nimport {type AuthStatus, type Editor} from './types.js'\n\nconst debug = subdebug('mcp:validateEditorTokens')\n\n/**\n * Validate existing MCP tokens for all configured editors.\n *\n * Collects unique tokens, validates each once against the Sanity API,\n * and sets `authStatus` on each editor that has a token.\n * Editors without a config or token are left unchanged.\n */\nexport async function validateEditorTokens(editors: Editor[]): Promise<void> {\n // Collect unique tokens and map them to their editors\n const tokenToEditors = new Map<string, Editor[]>()\n for (const editor of editors) {\n if (editor.existingToken) {\n const existing = tokenToEditors.get(editor.existingToken)\n if (existing) {\n existing.push(editor)\n } else {\n tokenToEditors.set(editor.existingToken, [editor])\n }\n }\n }\n\n if (tokenToEditors.size === 0) {\n debug('No existing tokens to validate')\n return\n }\n\n const editorCount = [...tokenToEditors.values()].reduce((sum, eds) => sum + eds.length, 0)\n debug('Validating %d unique token(s) across %d editor(s)', tokenToEditors.size, editorCount)\n\n // Validate all unique tokens in parallel to avoid stacking timeouts\n await Promise.all(\n [...tokenToEditors.entries()].map(async ([token, tokenEditors]) => {\n let status: AuthStatus\n try {\n const valid = await validateMCPToken(token)\n status = valid ? 'valid' : 'unauthorized'\n } catch (err) {\n // Network errors, timeouts, or unexpected failures — assume the token\n // is valid rather than falsely marking it as expired. We only mark\n // tokens as unauthorized when the server explicitly says so (401/403).\n debug('Token validation error (assuming valid): %s', err)\n status = 'valid'\n }\n\n debug(\n 'Token ending ...%s is %s (used by %s)',\n token.slice(-4),\n status,\n tokenEditors.map((e) => e.name).join(', '),\n )\n\n // Apply status to all editors sharing this token\n for (const editor of tokenEditors) {\n editor.authStatus = status\n }\n }),\n )\n}\n"],"names":["subdebug","validateMCPToken","debug","validateEditorTokens","editors","tokenToEditors","Map","editor","existingToken","existing","get","push","set","size","editorCount","values","reduce","sum","eds","length","Promise","all","entries","map","token","tokenEditors","status","valid","err","slice","e","name","join","authStatus"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AAEzC,SAAQC,gBAAgB,QAAO,wBAAuB;AAGtD,MAAMC,QAAQF,SAAS;AAEvB;;;;;;CAMC,GACD,OAAO,eAAeG,qBAAqBC,OAAiB;IAC1D,sDAAsD;IACtD,MAAMC,iBAAiB,IAAIC;IAC3B,KAAK,MAAMC,UAAUH,QAAS;QAC5B,IAAIG,OAAOC,aAAa,EAAE;YACxB,MAAMC,WAAWJ,eAAeK,GAAG,CAACH,OAAOC,aAAa;YACxD,IAAIC,UAAU;gBACZA,SAASE,IAAI,CAACJ;YAChB,OAAO;gBACLF,eAAeO,GAAG,CAACL,OAAOC,aAAa,EAAE;oBAACD;iBAAO;YACnD;QACF;IACF;IAEA,IAAIF,eAAeQ,IAAI,KAAK,GAAG;QAC7BX,MAAM;QACN;IACF;IAEA,MAAMY,cAAc;WAAIT,eAAeU,MAAM;KAAG,CAACC,MAAM,CAAC,CAACC,KAAKC,MAAQD,MAAMC,IAAIC,MAAM,EAAE;IACxFjB,MAAM,qDAAqDG,eAAeQ,IAAI,EAAEC;IAEhF,oEAAoE;IACpE,MAAMM,QAAQC,GAAG,CACf;WAAIhB,eAAeiB,OAAO;KAAG,CAACC,GAAG,CAAC,OAAO,CAACC,OAAOC,aAAa;QAC5D,IAAIC;QACJ,IAAI;YACF,MAAMC,QAAQ,MAAM1B,iBAAiBuB;YACrCE,SAASC,QAAQ,UAAU;QAC7B,EAAE,OAAOC,KAAK;YACZ,sEAAsE;YACtE,mEAAmE;YACnE,uEAAuE;YACvE1B,MAAM,+CAA+C0B;YACrDF,SAAS;QACX;QAEAxB,MACE,yCACAsB,MAAMK,KAAK,CAAC,CAAC,IACbH,QACAD,aAAaF,GAAG,CAAC,CAACO,IAAMA,EAAEC,IAAI,EAAEC,IAAI,CAAC;QAGvC,iDAAiD;QACjD,KAAK,MAAMzB,UAAUkB,aAAc;YACjClB,OAAO0B,UAAU,GAAGP;QACtB;IACF;AAEJ"}
@@ -2,6 +2,7 @@ import { existsSync } from 'node:fs';
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { applyEdits, modify } from 'jsonc-parser';
5
+ import { parse as parseToml, stringify as stringifyToml } from 'smol-toml';
5
6
  import { EDITOR_CONFIGS } from './editorConfigs.js';
6
7
  /**
7
8
  * Write MCP configuration to editor config file
@@ -10,27 +11,38 @@ import { EDITOR_CONFIGS } from './editorConfigs.js';
10
11
  * Note: Config parseability is already validated in detectAvailableEditors()
11
12
  */ export async function writeMCPConfig(editor, token) {
12
13
  const configPath = editor.configPath;
13
- const { buildServerConfig, configKey } = EDITOR_CONFIGS[editor.name];
14
- // Read existing content or start with empty object
15
- let content = '{}';
14
+ const { buildServerConfig, configKey, format } = EDITOR_CONFIGS[editor.name];
15
+ const serverConfig = buildServerConfig(token);
16
+ // Read existing content or start with empty object/document
17
+ let content = format === 'toml' ? '' : '{}';
16
18
  if (existsSync(configPath)) {
17
19
  const fileContent = await fs.readFile(configPath, 'utf8');
18
20
  if (fileContent.trim()) {
19
21
  content = fileContent;
20
22
  }
21
23
  }
22
- // Modify using jsonc-parser - preserves comments
23
- // Setting a nested path automatically creates intermediate objects
24
- const edits = modify(content, [
25
- configKey,
26
- 'Sanity'
27
- ], buildServerConfig(token), {
28
- formattingOptions: {
29
- insertSpaces: true,
30
- tabSize: 2
31
- }
32
- });
33
- content = applyEdits(content, edits);
24
+ if (format === 'toml') {
25
+ const tomlConfig = content.trim() ? parseToml(content) : {};
26
+ const existingServers = tomlConfig[configKey];
27
+ tomlConfig[configKey] = {
28
+ ...existingServers && typeof existingServers === 'object' ? existingServers : {},
29
+ Sanity: serverConfig
30
+ };
31
+ content = stringifyToml(tomlConfig);
32
+ } else {
33
+ // Modify using jsonc-parser - preserves comments
34
+ // Setting a nested path automatically creates intermediate objects
35
+ const edits = modify(content, [
36
+ configKey,
37
+ 'Sanity'
38
+ ], serverConfig, {
39
+ formattingOptions: {
40
+ insertSpaces: true,
41
+ tabSize: 2
42
+ }
43
+ });
44
+ content = applyEdits(content, edits);
45
+ }
34
46
  // Ensure parent directory exists and write
35
47
  await fs.mkdir(path.dirname(configPath), {
36
48
  recursive: true
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/mcp/writeMCPConfig.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {applyEdits, modify} from 'jsonc-parser'\n\nimport {EDITOR_CONFIGS} from './editorConfigs.js'\nimport {Editor} from './types.js'\n\n/**\n * Write MCP configuration to editor config file\n * Uses jsonc-parser's modify/applyEdits to preserve comments\n *\n * Note: Config parseability is already validated in detectAvailableEditors()\n */\nexport async function writeMCPConfig(editor: Editor, token: string): Promise<void> {\n const configPath = editor.configPath\n const {buildServerConfig, configKey} = EDITOR_CONFIGS[editor.name]\n\n // Read existing content or start with empty object\n let content = '{}'\n if (existsSync(configPath)) {\n const fileContent = await fs.readFile(configPath, 'utf8')\n if (fileContent.trim()) {\n content = fileContent\n }\n }\n\n // Modify using jsonc-parser - preserves comments\n // Setting a nested path automatically creates intermediate objects\n const edits = modify(content, [configKey, 'Sanity'], buildServerConfig(token), {\n formattingOptions: {insertSpaces: true, tabSize: 2},\n })\n content = applyEdits(content, edits)\n\n // Ensure parent directory exists and write\n await fs.mkdir(path.dirname(configPath), {recursive: true})\n await fs.writeFile(configPath, content, 'utf8')\n}\n"],"names":["existsSync","fs","path","applyEdits","modify","EDITOR_CONFIGS","writeMCPConfig","editor","token","configPath","buildServerConfig","configKey","name","content","fileContent","readFile","trim","edits","formattingOptions","insertSpaces","tabSize","mkdir","dirname","recursive","writeFile"],"mappings":"AAAA,SAAQA,UAAU,QAAO,UAAS;AAClC,OAAOC,QAAQ,mBAAkB;AACjC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,UAAU,EAAEC,MAAM,QAAO,eAAc;AAE/C,SAAQC,cAAc,QAAO,qBAAoB;AAGjD;;;;;CAKC,GACD,OAAO,eAAeC,eAAeC,MAAc,EAAEC,KAAa;IAChE,MAAMC,aAAaF,OAAOE,UAAU;IACpC,MAAM,EAACC,iBAAiB,EAAEC,SAAS,EAAC,GAAGN,cAAc,CAACE,OAAOK,IAAI,CAAC;IAElE,mDAAmD;IACnD,IAAIC,UAAU;IACd,IAAIb,WAAWS,aAAa;QAC1B,MAAMK,cAAc,MAAMb,GAAGc,QAAQ,CAACN,YAAY;QAClD,IAAIK,YAAYE,IAAI,IAAI;YACtBH,UAAUC;QACZ;IACF;IAEA,iDAAiD;IACjD,mEAAmE;IACnE,MAAMG,QAAQb,OAAOS,SAAS;QAACF;QAAW;KAAS,EAAED,kBAAkBF,QAAQ;QAC7EU,mBAAmB;YAACC,cAAc;YAAMC,SAAS;QAAC;IACpD;IACAP,UAAUV,WAAWU,SAASI;IAE9B,2CAA2C;IAC3C,MAAMhB,GAAGoB,KAAK,CAACnB,KAAKoB,OAAO,CAACb,aAAa;QAACc,WAAW;IAAI;IACzD,MAAMtB,GAAGuB,SAAS,CAACf,YAAYI,SAAS;AAC1C"}
1
+ {"version":3,"sources":["../../../src/actions/mcp/writeMCPConfig.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {applyEdits, modify} from 'jsonc-parser'\nimport {parse as parseToml, stringify as stringifyToml} from 'smol-toml'\n\nimport {EDITOR_CONFIGS} from './editorConfigs.js'\nimport {Editor} from './types.js'\n\ninterface TomlConfig {\n [key: string]: Record<string, unknown> | undefined\n}\n\n/**\n * Write MCP configuration to editor config file\n * Uses jsonc-parser's modify/applyEdits to preserve comments\n *\n * Note: Config parseability is already validated in detectAvailableEditors()\n */\nexport async function writeMCPConfig(editor: Editor, token: string): Promise<void> {\n const configPath = editor.configPath\n const {buildServerConfig, configKey, format} = EDITOR_CONFIGS[editor.name]\n const serverConfig = buildServerConfig(token)\n\n // Read existing content or start with empty object/document\n let content = format === 'toml' ? '' : '{}'\n if (existsSync(configPath)) {\n const fileContent = await fs.readFile(configPath, 'utf8')\n if (fileContent.trim()) {\n content = fileContent\n }\n }\n\n if (format === 'toml') {\n const tomlConfig = content.trim() ? (parseToml(content) as TomlConfig) : {}\n const existingServers = tomlConfig[configKey]\n\n tomlConfig[configKey] = {\n ...(existingServers && typeof existingServers === 'object' ? existingServers : {}),\n Sanity: serverConfig,\n }\n\n content = stringifyToml(tomlConfig)\n } else {\n // Modify using jsonc-parser - preserves comments\n // Setting a nested path automatically creates intermediate objects\n const edits = modify(content, [configKey, 'Sanity'], serverConfig, {\n formattingOptions: {insertSpaces: true, tabSize: 2},\n })\n content = applyEdits(content, edits)\n }\n\n // Ensure parent directory exists and write\n await fs.mkdir(path.dirname(configPath), {recursive: true})\n await fs.writeFile(configPath, content, 'utf8')\n}\n"],"names":["existsSync","fs","path","applyEdits","modify","parse","parseToml","stringify","stringifyToml","EDITOR_CONFIGS","writeMCPConfig","editor","token","configPath","buildServerConfig","configKey","format","name","serverConfig","content","fileContent","readFile","trim","tomlConfig","existingServers","Sanity","edits","formattingOptions","insertSpaces","tabSize","mkdir","dirname","recursive","writeFile"],"mappings":"AAAA,SAAQA,UAAU,QAAO,UAAS;AAClC,OAAOC,QAAQ,mBAAkB;AACjC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,UAAU,EAAEC,MAAM,QAAO,eAAc;AAC/C,SAAQC,SAASC,SAAS,EAAEC,aAAaC,aAAa,QAAO,YAAW;AAExE,SAAQC,cAAc,QAAO,qBAAoB;AAOjD;;;;;CAKC,GACD,OAAO,eAAeC,eAAeC,MAAc,EAAEC,KAAa;IAChE,MAAMC,aAAaF,OAAOE,UAAU;IACpC,MAAM,EAACC,iBAAiB,EAAEC,SAAS,EAAEC,MAAM,EAAC,GAAGP,cAAc,CAACE,OAAOM,IAAI,CAAC;IAC1E,MAAMC,eAAeJ,kBAAkBF;IAEvC,4DAA4D;IAC5D,IAAIO,UAAUH,WAAW,SAAS,KAAK;IACvC,IAAIhB,WAAWa,aAAa;QAC1B,MAAMO,cAAc,MAAMnB,GAAGoB,QAAQ,CAACR,YAAY;QAClD,IAAIO,YAAYE,IAAI,IAAI;YACtBH,UAAUC;QACZ;IACF;IAEA,IAAIJ,WAAW,QAAQ;QACrB,MAAMO,aAAaJ,QAAQG,IAAI,KAAMhB,UAAUa,WAA0B,CAAC;QAC1E,MAAMK,kBAAkBD,UAAU,CAACR,UAAU;QAE7CQ,UAAU,CAACR,UAAU,GAAG;YACtB,GAAIS,mBAAmB,OAAOA,oBAAoB,WAAWA,kBAAkB,CAAC,CAAC;YACjFC,QAAQP;QACV;QAEAC,UAAUX,cAAce;IAC1B,OAAO;QACL,iDAAiD;QACjD,mEAAmE;QACnE,MAAMG,QAAQtB,OAAOe,SAAS;YAACJ;YAAW;SAAS,EAAEG,cAAc;YACjES,mBAAmB;gBAACC,cAAc;gBAAMC,SAAS;YAAC;QACpD;QACAV,UAAUhB,WAAWgB,SAASO;IAChC;IAEA,2CAA2C;IAC3C,MAAMzB,GAAG6B,KAAK,CAAC5B,KAAK6B,OAAO,CAAClB,aAAa;QAACmB,WAAW;IAAI;IACzD,MAAM/B,GAAGgC,SAAS,CAACpB,YAAYM,SAAS;AAC1C"}
@@ -0,0 +1,32 @@
1
+ import readline from 'node:readline';
2
+ /**
3
+ * Stream an NDJSON file and build a Map from a key field to a value field.
4
+ *
5
+ * Only entries that contain the key field are indexed. If duplicate keys exist,
6
+ * the last entry wins.
7
+ *
8
+ * @internal
9
+ */ export async function buildNdjsonIndex(ndjson, keyField, valueField) {
10
+ const lines = readline.createInterface({
11
+ input: ndjson
12
+ });
13
+ const index = new Map();
14
+ try {
15
+ for await (const line of lines){
16
+ const trimmed = line.trim();
17
+ if (trimmed) {
18
+ const entry = JSON.parse(trimmed);
19
+ if (entry[keyField] != null) {
20
+ index.set(entry[keyField], entry[valueField]);
21
+ }
22
+ }
23
+ }
24
+ } finally{
25
+ lines.close();
26
+ // Explicitly destroy the underlying stream to prevent file descriptor leaks
27
+ ndjson.destroy();
28
+ }
29
+ return index;
30
+ }
31
+
32
+ //# sourceMappingURL=buildNdjsonIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/media/buildNdjsonIndex.ts"],"sourcesContent":["import readline from 'node:readline'\nimport {Readable} from 'node:stream'\n\n/**\n * Stream an NDJSON file and build a Map from a key field to a value field.\n *\n * Only entries that contain the key field are indexed. If duplicate keys exist,\n * the last entry wins.\n *\n * @internal\n */\nexport async function buildNdjsonIndex<Value = unknown>(\n ndjson: Readable,\n keyField: string,\n valueField: string,\n): Promise<Map<string, Value>> {\n const lines = readline.createInterface({\n input: ndjson,\n })\n\n const index = new Map<string, Value>()\n\n try {\n for await (const line of lines) {\n const trimmed = line.trim()\n if (trimmed) {\n const entry = JSON.parse(trimmed)\n if (entry[keyField] != null) {\n index.set(entry[keyField], entry[valueField])\n }\n }\n }\n } finally {\n lines.close()\n // Explicitly destroy the underlying stream to prevent file descriptor leaks\n ndjson.destroy()\n }\n\n return index\n}\n"],"names":["readline","buildNdjsonIndex","ndjson","keyField","valueField","lines","createInterface","input","index","Map","line","trimmed","trim","entry","JSON","parse","set","close","destroy"],"mappings":"AAAA,OAAOA,cAAc,gBAAe;AAGpC;;;;;;;CAOC,GACD,OAAO,eAAeC,iBACpBC,MAAgB,EAChBC,QAAgB,EAChBC,UAAkB;IAElB,MAAMC,QAAQL,SAASM,eAAe,CAAC;QACrCC,OAAOL;IACT;IAEA,MAAMM,QAAQ,IAAIC;IAElB,IAAI;QACF,WAAW,MAAMC,QAAQL,MAAO;YAC9B,MAAMM,UAAUD,KAAKE,IAAI;YACzB,IAAID,SAAS;gBACX,MAAME,QAAQC,KAAKC,KAAK,CAACJ;gBACzB,IAAIE,KAAK,CAACV,SAAS,IAAI,MAAM;oBAC3BK,MAAMQ,GAAG,CAACH,KAAK,CAACV,SAAS,EAAEU,KAAK,CAACT,WAAW;gBAC9C;YACF;QACF;IACF,SAAU;QACRC,MAAMY,KAAK;QACX,4EAA4E;QAC5Ef,OAAOgB,OAAO;IAChB;IAEA,OAAOV;AACT"}
@@ -1,10 +1,8 @@
1
1
  import { access, readdir } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { tryGetDefaultExport } from '@sanity/cli-core';
3
+ import { importModule } from '@sanity/cli-core';
4
4
  import { validateMediaLibraryAssetAspect } from '@sanity/schema/_internal';
5
5
  import { isAssetAspect } from '@sanity/types';
6
- import { getTsconfig } from 'get-tsconfig';
7
- import { tsImport } from 'tsx/esm/api';
8
6
  /**
9
7
  * File extensions that are considered valid aspect definition files
10
8
  */ const ASPECT_FILE_EXTENSIONS = new Set([
@@ -39,8 +37,6 @@ import { tsImport } from 'tsx/esm/api';
39
37
  });
40
38
  // Filter for valid aspect files
41
39
  const aspectFiles = entries.filter((entry)=>entry.isFile() && ASPECT_FILE_EXTENSIONS.has(path.extname(entry.name)));
42
- // Get tsconfig for TypeScript compilation
43
- const tsconfig = getTsconfig(aspectsPath);
44
40
  // Import and validate all aspect files
45
41
  const aspects = [];
46
42
  for (const file of aspectFiles){
@@ -48,12 +44,7 @@ import { tsImport } from 'tsx/esm/api';
48
44
  const filePath = path.resolve(aspectsPath, filename);
49
45
  try {
50
46
  // Dynamically import the aspect file with TypeScript support
51
- const aspectModule = await tsImport(filePath, {
52
- parentURL: import.meta.url,
53
- tsconfig: tsconfig?.path
54
- });
55
- // Get the default export
56
- const maybeAspect = tryGetDefaultExport(aspectModule);
47
+ const maybeAspect = await importModule(filePath);
57
48
  // Check if user wants to filter this aspect
58
49
  if (!filterAspects(maybeAspect)) {
59
50
  continue;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/media/importAspects.ts"],"sourcesContent":["import {access, readdir} from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {tryGetDefaultExport} from '@sanity/cli-core'\nimport {validateMediaLibraryAssetAspect} from '@sanity/schema/_internal'\nimport {\n isAssetAspect,\n type MediaLibraryAssetAspectDocument,\n type SchemaValidationProblem,\n} from '@sanity/types'\nimport {getTsconfig} from 'get-tsconfig'\nimport {tsImport} from 'tsx/esm/api'\n\n/**\n * File extensions that are considered valid aspect definition files\n */\nconst ASPECT_FILE_EXTENSIONS = new Set(['.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx'])\n\n/**\n * Type for an aspect that has been validated\n */\ninterface ValidAspect {\n aspect: MediaLibraryAssetAspectDocument\n filename: string\n status: 'valid'\n validationErrors: never[]\n}\n\n/**\n * Type for an aspect that failed validation\n */\ninterface InvalidAspect {\n aspect: unknown\n filename: string\n status: 'invalid'\n validationErrors: SchemaValidationProblem[][]\n}\n\n/**\n * Union type for aspect containers\n */\ntype AspectContainer = InvalidAspect | ValidAspect\n\n/**\n * Options for importing aspects\n */\ninterface ImportAspectsOptions {\n /**\n * Path to the directory containing aspect definition files\n */\n aspectsPath: string\n\n /**\n * Optional filter function to determine which aspects to include\n */\n filterAspects?: (aspect: unknown) => boolean\n}\n\n/**\n * Result of importing aspects, grouped by validation status\n */\ninterface ImportAspectsResult {\n invalid: InvalidAspect[]\n valid: ValidAspect[]\n}\n\n/**\n * Import and validate aspect definition files from a directory\n *\n * This function reads all TypeScript/JavaScript files from the specified directory,\n * dynamically imports them using tsx for TypeScript support, validates them,\n * and returns them grouped by validation status.\n *\n * @param options - Options for importing aspects\n * @returns Promise resolving to valid and invalid aspects\n * @internal\n */\nexport async function importAspects(options: ImportAspectsOptions): Promise<ImportAspectsResult> {\n const {aspectsPath, filterAspects = () => true} = options\n\n // Check if directory exists\n try {\n await access(aspectsPath)\n } catch {\n throw new Error(`Aspects directory does not exist: ${aspectsPath}`)\n }\n\n // Read directory entries\n const entries = await readdir(aspectsPath, {withFileTypes: true})\n\n // Filter for valid aspect files\n const aspectFiles = entries.filter(\n (entry) => entry.isFile() && ASPECT_FILE_EXTENSIONS.has(path.extname(entry.name)),\n )\n\n // Get tsconfig for TypeScript compilation\n const tsconfig = getTsconfig(aspectsPath)\n\n // Import and validate all aspect files\n const aspects: AspectContainer[] = []\n\n for (const file of aspectFiles) {\n const filename = file.name\n const filePath = path.resolve(aspectsPath, filename)\n\n try {\n // Dynamically import the aspect file with TypeScript support\n const aspectModule = await tsImport(filePath, {\n parentURL: import.meta.url,\n tsconfig: tsconfig?.path,\n })\n\n // Get the default export\n const maybeAspect = tryGetDefaultExport(aspectModule)\n\n // Check if user wants to filter this aspect\n if (!filterAspects(maybeAspect)) {\n continue\n }\n\n // Validate that it's an asset aspect\n if (!isAssetAspect(maybeAspect)) {\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'invalid',\n validationErrors: [],\n })\n continue\n }\n\n // Validate the aspect schema\n const [valid, errors] = validateMediaLibraryAssetAspect(maybeAspect.definition)\n\n if (!valid) {\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'invalid',\n validationErrors: errors,\n })\n continue\n }\n\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'valid',\n validationErrors: [],\n })\n } catch (error) {\n aspects.push({\n aspect: null,\n filename,\n status: 'invalid',\n validationErrors: [\n [\n {\n message: `Failed to import file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n severity: 'error',\n },\n ],\n ],\n })\n }\n }\n\n // Group by validation status\n const result: ImportAspectsResult = {\n invalid: aspects.filter((a): a is InvalidAspect => a.status === 'invalid'),\n valid: aspects.filter((a): a is ValidAspect => a.status === 'valid'),\n }\n\n return result\n}\n"],"names":["access","readdir","path","tryGetDefaultExport","validateMediaLibraryAssetAspect","isAssetAspect","getTsconfig","tsImport","ASPECT_FILE_EXTENSIONS","Set","importAspects","options","aspectsPath","filterAspects","Error","entries","withFileTypes","aspectFiles","filter","entry","isFile","has","extname","name","tsconfig","aspects","file","filename","filePath","resolve","aspectModule","parentURL","url","maybeAspect","push","aspect","status","validationErrors","valid","errors","definition","error","message","severity","result","invalid","a"],"mappings":"AAAA,SAAQA,MAAM,EAAEC,OAAO,QAAO,mBAAkB;AAChD,OAAOC,UAAU,YAAW;AAE5B,SAAQC,mBAAmB,QAAO,mBAAkB;AACpD,SAAQC,+BAA+B,QAAO,2BAA0B;AACxE,SACEC,aAAa,QAGR,gBAAe;AACtB,SAAQC,WAAW,QAAO,eAAc;AACxC,SAAQC,QAAQ,QAAO,cAAa;AAEpC;;CAEC,GACD,MAAMC,yBAAyB,IAAIC,IAAI;IAAC;IAAO;IAAQ;IAAQ;IAAQ;IAAO;CAAO;AAkDrF;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,WAAW,EAAEC,gBAAgB,IAAM,IAAI,EAAC,GAAGF;IAElD,4BAA4B;IAC5B,IAAI;QACF,MAAMX,OAAOY;IACf,EAAE,OAAM;QACN,MAAM,IAAIE,MAAM,CAAC,kCAAkC,EAAEF,aAAa;IACpE;IAEA,yBAAyB;IACzB,MAAMG,UAAU,MAAMd,QAAQW,aAAa;QAACI,eAAe;IAAI;IAE/D,gCAAgC;IAChC,MAAMC,cAAcF,QAAQG,MAAM,CAChC,CAACC,QAAUA,MAAMC,MAAM,MAAMZ,uBAAuBa,GAAG,CAACnB,KAAKoB,OAAO,CAACH,MAAMI,IAAI;IAGjF,0CAA0C;IAC1C,MAAMC,WAAWlB,YAAYM;IAE7B,uCAAuC;IACvC,MAAMa,UAA6B,EAAE;IAErC,KAAK,MAAMC,QAAQT,YAAa;QAC9B,MAAMU,WAAWD,KAAKH,IAAI;QAC1B,MAAMK,WAAW1B,KAAK2B,OAAO,CAACjB,aAAae;QAE3C,IAAI;YACF,6DAA6D;YAC7D,MAAMG,eAAe,MAAMvB,SAASqB,UAAU;gBAC5CG,WAAW,YAAYC,GAAG;gBAC1BR,UAAUA,UAAUtB;YACtB;YAEA,yBAAyB;YACzB,MAAM+B,cAAc9B,oBAAoB2B;YAExC,4CAA4C;YAC5C,IAAI,CAACjB,cAAcoB,cAAc;gBAC/B;YACF;YAEA,qCAAqC;YACrC,IAAI,CAAC5B,cAAc4B,cAAc;gBAC/BR,QAAQS,IAAI,CAAC;oBACXC,QAAQF;oBACRN;oBACAS,QAAQ;oBACRC,kBAAkB,EAAE;gBACtB;gBACA;YACF;YAEA,6BAA6B;YAC7B,MAAM,CAACC,OAAOC,OAAO,GAAGnC,gCAAgC6B,YAAYO,UAAU;YAE9E,IAAI,CAACF,OAAO;gBACVb,QAAQS,IAAI,CAAC;oBACXC,QAAQF;oBACRN;oBACAS,QAAQ;oBACRC,kBAAkBE;gBACpB;gBACA;YACF;YAEAd,QAAQS,IAAI,CAAC;gBACXC,QAAQF;gBACRN;gBACAS,QAAQ;gBACRC,kBAAkB,EAAE;YACtB;QACF,EAAE,OAAOI,OAAO;YACdhB,QAAQS,IAAI,CAAC;gBACXC,QAAQ;gBACRR;gBACAS,QAAQ;gBACRC,kBAAkB;oBAChB;wBACE;4BACEK,SAAS,CAAC,uBAAuB,EAAED,iBAAiB3B,QAAQ2B,MAAMC,OAAO,GAAG,iBAAiB;4BAC7FC,UAAU;wBACZ;qBACD;iBACF;YACH;QACF;IACF;IAEA,6BAA6B;IAC7B,MAAMC,SAA8B;QAClCC,SAASpB,QAAQP,MAAM,CAAC,CAAC4B,IAA0BA,EAAEV,MAAM,KAAK;QAChEE,OAAOb,QAAQP,MAAM,CAAC,CAAC4B,IAAwBA,EAAEV,MAAM,KAAK;IAC9D;IAEA,OAAOQ;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/media/importAspects.ts"],"sourcesContent":["import {access, readdir} from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {importModule} from '@sanity/cli-core'\nimport {validateMediaLibraryAssetAspect} from '@sanity/schema/_internal'\nimport {\n isAssetAspect,\n type MediaLibraryAssetAspectDocument,\n type SchemaValidationProblem,\n} from '@sanity/types'\n\n/**\n * File extensions that are considered valid aspect definition files\n */\nconst ASPECT_FILE_EXTENSIONS = new Set(['.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx'])\n\n/**\n * Type for an aspect that has been validated\n */\ninterface ValidAspect {\n aspect: MediaLibraryAssetAspectDocument\n filename: string\n status: 'valid'\n validationErrors: never[]\n}\n\n/**\n * Type for an aspect that failed validation\n */\ninterface InvalidAspect {\n aspect: unknown\n filename: string\n status: 'invalid'\n validationErrors: SchemaValidationProblem[][]\n}\n\n/**\n * Union type for aspect containers\n */\ntype AspectContainer = InvalidAspect | ValidAspect\n\n/**\n * Options for importing aspects\n */\ninterface ImportAspectsOptions {\n /**\n * Path to the directory containing aspect definition files\n */\n aspectsPath: string\n\n /**\n * Optional filter function to determine which aspects to include\n */\n filterAspects?: (aspect: unknown) => boolean\n}\n\n/**\n * Result of importing aspects, grouped by validation status\n */\ninterface ImportAspectsResult {\n invalid: InvalidAspect[]\n valid: ValidAspect[]\n}\n\n/**\n * Import and validate aspect definition files from a directory\n *\n * This function reads all TypeScript/JavaScript files from the specified directory,\n * dynamically imports them using tsx for TypeScript support, validates them,\n * and returns them grouped by validation status.\n *\n * @param options - Options for importing aspects\n * @returns Promise resolving to valid and invalid aspects\n * @internal\n */\nexport async function importAspects(options: ImportAspectsOptions): Promise<ImportAspectsResult> {\n const {aspectsPath, filterAspects = () => true} = options\n\n // Check if directory exists\n try {\n await access(aspectsPath)\n } catch {\n throw new Error(`Aspects directory does not exist: ${aspectsPath}`)\n }\n\n // Read directory entries\n const entries = await readdir(aspectsPath, {withFileTypes: true})\n\n // Filter for valid aspect files\n const aspectFiles = entries.filter(\n (entry) => entry.isFile() && ASPECT_FILE_EXTENSIONS.has(path.extname(entry.name)),\n )\n\n // Import and validate all aspect files\n const aspects: AspectContainer[] = []\n\n for (const file of aspectFiles) {\n const filename = file.name\n const filePath = path.resolve(aspectsPath, filename)\n\n try {\n // Dynamically import the aspect file with TypeScript support\n const maybeAspect = await importModule(filePath)\n\n // Check if user wants to filter this aspect\n if (!filterAspects(maybeAspect)) {\n continue\n }\n\n // Validate that it's an asset aspect\n if (!isAssetAspect(maybeAspect)) {\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'invalid',\n validationErrors: [],\n })\n continue\n }\n\n // Validate the aspect schema\n const [valid, errors] = validateMediaLibraryAssetAspect(maybeAspect.definition)\n\n if (!valid) {\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'invalid',\n validationErrors: errors,\n })\n continue\n }\n\n aspects.push({\n aspect: maybeAspect,\n filename,\n status: 'valid',\n validationErrors: [],\n })\n } catch (error) {\n aspects.push({\n aspect: null,\n filename,\n status: 'invalid',\n validationErrors: [\n [\n {\n message: `Failed to import file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n severity: 'error',\n },\n ],\n ],\n })\n }\n }\n\n // Group by validation status\n const result: ImportAspectsResult = {\n invalid: aspects.filter((a): a is InvalidAspect => a.status === 'invalid'),\n valid: aspects.filter((a): a is ValidAspect => a.status === 'valid'),\n }\n\n return result\n}\n"],"names":["access","readdir","path","importModule","validateMediaLibraryAssetAspect","isAssetAspect","ASPECT_FILE_EXTENSIONS","Set","importAspects","options","aspectsPath","filterAspects","Error","entries","withFileTypes","aspectFiles","filter","entry","isFile","has","extname","name","aspects","file","filename","filePath","resolve","maybeAspect","push","aspect","status","validationErrors","valid","errors","definition","error","message","severity","result","invalid","a"],"mappings":"AAAA,SAAQA,MAAM,EAAEC,OAAO,QAAO,mBAAkB;AAChD,OAAOC,UAAU,YAAW;AAE5B,SAAQC,YAAY,QAAO,mBAAkB;AAC7C,SAAQC,+BAA+B,QAAO,2BAA0B;AACxE,SACEC,aAAa,QAGR,gBAAe;AAEtB;;CAEC,GACD,MAAMC,yBAAyB,IAAIC,IAAI;IAAC;IAAO;IAAQ;IAAQ;IAAQ;IAAO;CAAO;AAkDrF;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,WAAW,EAAEC,gBAAgB,IAAM,IAAI,EAAC,GAAGF;IAElD,4BAA4B;IAC5B,IAAI;QACF,MAAMT,OAAOU;IACf,EAAE,OAAM;QACN,MAAM,IAAIE,MAAM,CAAC,kCAAkC,EAAEF,aAAa;IACpE;IAEA,yBAAyB;IACzB,MAAMG,UAAU,MAAMZ,QAAQS,aAAa;QAACI,eAAe;IAAI;IAE/D,gCAAgC;IAChC,MAAMC,cAAcF,QAAQG,MAAM,CAChC,CAACC,QAAUA,MAAMC,MAAM,MAAMZ,uBAAuBa,GAAG,CAACjB,KAAKkB,OAAO,CAACH,MAAMI,IAAI;IAGjF,uCAAuC;IACvC,MAAMC,UAA6B,EAAE;IAErC,KAAK,MAAMC,QAAQR,YAAa;QAC9B,MAAMS,WAAWD,KAAKF,IAAI;QAC1B,MAAMI,WAAWvB,KAAKwB,OAAO,CAAChB,aAAac;QAE3C,IAAI;YACF,6DAA6D;YAC7D,MAAMG,cAAc,MAAMxB,aAAasB;YAEvC,4CAA4C;YAC5C,IAAI,CAACd,cAAcgB,cAAc;gBAC/B;YACF;YAEA,qCAAqC;YACrC,IAAI,CAACtB,cAAcsB,cAAc;gBAC/BL,QAAQM,IAAI,CAAC;oBACXC,QAAQF;oBACRH;oBACAM,QAAQ;oBACRC,kBAAkB,EAAE;gBACtB;gBACA;YACF;YAEA,6BAA6B;YAC7B,MAAM,CAACC,OAAOC,OAAO,GAAG7B,gCAAgCuB,YAAYO,UAAU;YAE9E,IAAI,CAACF,OAAO;gBACVV,QAAQM,IAAI,CAAC;oBACXC,QAAQF;oBACRH;oBACAM,QAAQ;oBACRC,kBAAkBE;gBACpB;gBACA;YACF;YAEAX,QAAQM,IAAI,CAAC;gBACXC,QAAQF;gBACRH;gBACAM,QAAQ;gBACRC,kBAAkB,EAAE;YACtB;QACF,EAAE,OAAOI,OAAO;YACdb,QAAQM,IAAI,CAAC;gBACXC,QAAQ;gBACRL;gBACAM,QAAQ;gBACRC,kBAAkB;oBAChB;wBACE;4BACEK,SAAS,CAAC,uBAAuB,EAAED,iBAAiBvB,QAAQuB,MAAMC,OAAO,GAAG,iBAAiB;4BAC7FC,UAAU;wBACZ;qBACD;iBACF;YACH;QACF;IACF;IAEA,6BAA6B;IAC7B,MAAMC,SAA8B;QAClCC,SAASjB,QAAQN,MAAM,CAAC,CAACwB,IAA0BA,EAAEV,MAAM,KAAK;QAChEE,OAAOV,QAAQN,MAAM,CAAC,CAACwB,IAAwBA,EAAEV,MAAM,KAAK;IAC9D;IAEA,OAAOQ;AACT"}
@@ -8,13 +8,12 @@ import { pipeline } from 'node:stream/promises';
8
8
  import { styleText } from 'node:util';
9
9
  import gunzipMaybe from 'gunzip-maybe';
10
10
  // @ts-expect-error `peek-stream` module currently untyped
11
- import isTar from 'is-tar';
12
- // @ts-expect-error `peek-stream` module currently untyped
13
11
  import peek from 'peek-stream';
14
12
  import { catchError, EMPTY, filter, from, map, mergeMap, mergeWith, of, switchMap, tap, zip } from 'rxjs';
15
13
  import tar from 'tar-fs';
16
14
  import { glob } from 'tinyglobby';
17
- import { findNdjsonEntry } from '../../util/findNdjsonEntry.js';
15
+ import { isTar } from '../../util/isTar.js';
16
+ import { buildNdjsonIndex } from './buildNdjsonIndex.js';
18
17
  import { importMediaDebug } from './importMediaDebug.js';
19
18
  const DEFAULT_CONCURRENCY = 6;
20
19
  export function importer(options) {
@@ -23,15 +22,20 @@ export function importer(options) {
23
22
  if (fileCount === 0) {
24
23
  throw new Error('No assets to import');
25
24
  }
26
- const context = {
27
- ...options,
28
- ndjson: ()=>createReadStream(aspectsNdjsonPath),
29
- workingPath
30
- };
31
- return from(files).pipe(switchMap((file)=>zip(of('file'), of(file))), mergeWith(from(images).pipe(switchMap((file)=>zip(of('image'), of(file))))), fetchExistingAssets(context), uploadAsset(context), resolveAspectData(context), setAspects(context), map((asset)=>({
32
- asset,
33
- fileCount
34
- })));
25
+ // Stream the ndjson file once and build an index to avoid creating
26
+ // multiple read streams (which causes file descriptor leaks)
27
+ const aspectsIndexPromise = buildNdjsonIndex(createReadStream(aspectsNdjsonPath), 'filename', 'aspects');
28
+ return from(aspectsIndexPromise).pipe(mergeMap((aspectsIndex)=>{
29
+ const context = {
30
+ ...options,
31
+ aspectsIndex,
32
+ workingPath
33
+ };
34
+ return from(files).pipe(switchMap((file)=>zip(of('file'), of(file))), mergeWith(from(images).pipe(switchMap((file)=>zip(of('image'), of(file))))), fetchExistingAssets(context), uploadAsset(context), resolveAspectData(context), setAspects(context), map((asset)=>({
35
+ asset,
36
+ fileCount
37
+ })));
38
+ }));
35
39
  }));
36
40
  }
37
41
  /**
@@ -141,14 +145,14 @@ function fetchExistingAssets({ client, workingPath }) {
141
145
  });
142
146
  }
143
147
  /**
144
- * Find the first matching entry in the provided NDJSON stream and attach it to the asset object.
148
+ * Find the first matching entry in the cached aspect data and attach it to the asset object.
145
149
  *
146
150
  * @internal
147
- */ function resolveAspectData({ ndjson }) {
148
- return mergeMap((resolvedAsset)=>from(findNdjsonEntry(ndjson(), (line)=>typeof line === 'object' && line !== null && 'filename' in line && line.filename === resolvedAsset.originalFilename)).pipe(map((aspectsFromImport)=>({
149
- ...resolvedAsset,
150
- aspects: aspectsFromImport?.aspects
151
- }))));
151
+ */ function resolveAspectData({ aspectsIndex }) {
152
+ return map((resolvedAsset)=>({
153
+ ...resolvedAsset,
154
+ aspects: aspectsIndex.get(resolvedAsset.originalFilename)
155
+ }));
152
156
  }
153
157
  // TODO: Batch mutations to reduce HTTP request count.
154
158
  export function setAspects({ client, replaceAspects }) {